Skip to content

Commit

Permalink
time_span.py has been rewritten to be represented using float
Browse files Browse the repository at this point in the history
  • Loading branch information
MangelMaxime committed Nov 22, 2023
1 parent 43f34f9 commit fa287de
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 85 deletions.
16 changes: 8 additions & 8 deletions src/Fable.Transforms/Python/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3027,14 +3027,14 @@ let timeSpans (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr o

Helper.LibCall(com, "time_span", meth, t, args, i.SignatureArgTypes, ?loc = r)
|> Some
| "FromMilliseconds" ->
//TypeCast(args.Head, t) |> Some
Helper.LibCall(com, "time_span", "from_milliseconds", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r)
|> Some
| "get_TotalMilliseconds" ->
//TypeCast(thisArg.Value, t) |> Some
Helper.LibCall(com, "time_span", "to_milliseconds", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r)
|> Some
// | "FromMilliseconds" ->
// //TypeCast(args.Head, t) |> Some
// Helper.LibCall(com, "time_span", "from_milliseconds", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r)
// |> Some
// | "get_TotalMilliseconds" ->
// //TypeCast(thisArg.Value, t) |> Some
// Helper.LibCall(com, "time_span", "to_milliseconds", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r)
// |> Some
| "ToString" when (args.Length = 1) ->
"TimeSpan.ToString with one argument is not supported, because it depends of local culture, please add CultureInfo.InvariantCulture"
|> addError com ctx.InlinePath r
Expand Down
9 changes: 7 additions & 2 deletions src/fable-library-py/fable_library/date.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@

from .types import FSharpRef
from .util import DateKind
from .time_span import TimeSpan, create as create_time_span


formatRegExp = re.compile(r"(\w)\1*")


def op_subtraction(x: datetime, y: datetime) -> timedelta:
return x - y
def op_subtraction(x: datetime, y: datetime) -> TimeSpan:
delta = x - y
# ts.microseconds only contains the microseconds provided to the constructor
# so we need to calculate the total microseconds ourselves
deltaMicroseconds = delta.days * (24*3600) + delta.seconds * 10**6 + delta.microseconds
return create_time_span(0,0,0,0,0,deltaMicroseconds)


def create(
Expand Down
27 changes: 17 additions & 10 deletions src/fable-library-py/fable_library/date_offset.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

from datetime import datetime, timedelta, timezone

from . import time_span
from .time_span import TimeSpan
from .types import FSharpRef

def timedelta_total_microseconds(td: timedelta) -> int:
# timedelta doesn't expose total_microseconds
# so we need to calculate it ourselves
return td.days * (24*3600) + td.seconds * 10**6 + td.microseconds

def add(d: datetime, ts: timedelta) -> datetime:
return d + ts
Expand All @@ -30,17 +36,18 @@ def create(
h: int,
m: int,
s: int,
ms: int | timedelta,
offset: timedelta | None = None,
ms: int | TimeSpan,
offset: TimeSpan | None = None,
) -> datetime:
if isinstance(ms, timedelta):
offset = ms
pythonOffset: timedelta | None = None
if isinstance(ms, TimeSpan):
pythonOffset = timedelta(microseconds=time_span.total_microseconds(ms))
ms = 0

if offset is None:
if pythonOffset is None:
return datetime(year, month, day, h, m, s, ms)

tzinfo = timezone(offset)
tzinfo = timezone(pythonOffset)
return datetime(year, month, day, h, m, s, ms, tzinfo=tzinfo)


Expand All @@ -56,11 +63,11 @@ def op_addition(x: datetime, y: timedelta) -> datetime:
return x + y


def op_subtraction(x: datetime, y: datetime | timedelta) -> datetime | timedelta:
if isinstance(y, timedelta):
return x - y
def op_subtraction(x: datetime, y: datetime | TimeSpan) -> datetime | TimeSpan:
if isinstance(y, TimeSpan):
return x - timedelta(microseconds=time_span.total_microseconds(y))

return x - y
return time_span.create(0,0,0,0,0,timedelta_total_microseconds(x - y))


def min_value() -> datetime:
Expand Down
170 changes: 106 additions & 64 deletions src/fable-library-py/fable_library/time_span.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,118 +6,155 @@
from .util import pad_left_and_right_with_zeros, pad_with_zeros


def total_seconds(ts: timedelta) -> float:
return ts.total_seconds()
# TimeSpan is represented as an int which is the Tick value
# We can recompute everything from this value
class TimeSpan(int):
pass


def total_days(ts: timedelta) -> float:
return total_seconds(ts) / 86400
def create(
days: float = 0,
hours: float | None = None,
minutes: float | None = None,
seconds: float | None = None,
milliseconds: float | None = None,
microseconds: float | None = None,
) -> TimeSpan:
match (days, hours, minutes, seconds, milliseconds, microseconds):
# ticks constructor
case (_, None, None, None, None, None):
return TimeSpan(days)
# hours, minutes, seconds constructor
case (_, _, _, None, None, None):
print("hours, minutes, seconds constructor")
seconds = minutes
minutes = hours
hours = days
days = 0
# others constructor follows the correct order of arguments
case _:
pass

return TimeSpan(
days * 864000000000
+ (hours or 0) * 36000000000
+ (minutes or 0) * 600000000
+ (seconds or 0) * 10000000
+ (milliseconds or 0) * 10000
+ (microseconds or 0) * 10
)


def total_minutes(ts: timedelta) -> float:
return total_seconds(ts) / 60
def total_nanoseconds(ts: TimeSpan) -> float:
# We store timespan as the Tick value so nanoseconds step is 100
return ts * 100


def total_hours(ts: timedelta) -> float:
return total_seconds(ts) / 3600
def total_microseconds(ts: TimeSpan) -> float:
return ts / 10


def from_milliseconds(msecs: int) -> timedelta:
return timedelta(milliseconds=msecs)
def total_milliseconds(ts: TimeSpan) -> float:
return ts / 10000


def from_ticks(ticks: int) -> timedelta:
return timedelta(microseconds=ticks // 10)
def total_seconds(ts: TimeSpan) -> float:
return ts / 10000000


def from_seconds(s: int) -> timedelta:
return timedelta(seconds=s)
def total_minutes(ts: TimeSpan) -> float:
return ts / 600000000


def from_minutes(m: int) -> timedelta:
return timedelta(minutes=m)
def total_hours(ts: TimeSpan) -> float:
return ts / 36000000000


def from_hours(h: int) -> timedelta:
return timedelta(hours=h)
def total_days(ts: TimeSpan) -> float:
return ts / 864000000000

def from_microseconds(micros: float) -> TimeSpan:
return create(0,0,0,0,0,micros)

def from_days(d: int) -> timedelta:
return timedelta(days=d)
def from_milliseconds(msecs: int) -> TimeSpan:
return create(0,0,0,0,msecs)


def to_milliseconds(td: timedelta) -> int:
return int(td.total_seconds() * 1000)
def from_ticks(ticks: int) -> TimeSpan:
return create(ticks)


def days(ts: timedelta) -> int:
return int(total_seconds(ts) / 86400)
def from_seconds(s: int) -> TimeSpan:
return create(0, 0, s)


def hours(ts: timedelta) -> int:
return int(abs(total_seconds(ts)) % 86400 / 3600)
def from_minutes(m: int) -> TimeSpan:
return create(0, m, 0)


def minutes(ts: timedelta) -> int:
return int(abs(total_seconds(ts)) % 3600 / 60)
def from_hours(h: int) -> TimeSpan:
return create(h, 0, 0)


def seconds(ts: timedelta) -> int:
return int(abs(total_seconds(ts)) % 60)
def from_days(d: int) -> TimeSpan:
return create(d, 0, 0, 0)


def milliseconds(ts: timedelta) -> int:
return int(total_seconds(ts) % 1 * 1000)
def ticks(ts: TimeSpan) -> int:
return int(ts)


def ticks(ts: timedelta) -> int:
return int(total_seconds(ts) * 10000000)
def microseconds(ts: TimeSpan) -> int:
return int(ts % 10000 / 10)


def negate(ts: timedelta) -> timedelta:
return -ts
def milliseconds(ts: TimeSpan) -> int:
return int(ts % 10000000 / 10000)


def duration(ts: timedelta) -> timedelta:
if ts < timedelta(0):
return -ts
def seconds(ts: TimeSpan) -> int:
return int(ts % 600000000 / 10000000)

return ts

def minutes(ts: TimeSpan) -> int:
return int(ts % 36000000000 / 600000000)

def add(ts: timedelta, other: timedelta) -> timedelta:
return ts + other

def hours(ts: TimeSpan) -> int:
return int(ts % 864000000000 / 36000000000)

def subtract(ts: timedelta, other: timedelta) -> timedelta:
return ts - other

def days(ts: TimeSpan) -> int:
return int(ts / 864000000000)

def multiply(ts: timedelta, factor: int) -> timedelta:
return ts * factor

def negate(ts: TimeSpan) -> TimeSpan:
return TimeSpan(-ts)

def divide(ts: timedelta, divisor: int) -> timedelta:
return ts / divisor

def duration(ts: TimeSpan) -> TimeSpan:
return TimeSpan(abs(int(ts)))

def create(
d: int = 0,
h: int | None = None,
m: int | None = None,
s: int | None = None,
ms: int | None = None,
) -> timedelta:
if h is None and m is None and s is None and ms is None:
return from_ticks(d)

elif s is None and ms is None:
return timedelta(hours=d or 0, minutes=h or 0, seconds=m or 0)
def add(ts: TimeSpan, other: TimeSpan) -> TimeSpan:
return TimeSpan(ts + other)


def subtract(ts: TimeSpan, other: TimeSpan) -> TimeSpan:
return TimeSpan(ts - other)


return timedelta(days=d, hours=h or 0, minutes=m or 0, seconds=s or 0, milliseconds=ms or 0)
def multiply(ts: TimeSpan, factor: float) -> TimeSpan:
# We represents TimeSpan as a Tick which can't be a float
# This also allows us
return TimeSpan(int(ts * factor))


def to_string(ts: timedelta, format: str = "c", _provider: Any | None = None) -> str:
def divide(ts: TimeSpan, divisor: float) -> TimeSpan:
return TimeSpan(int(ts / divisor))


def to_string(ts: TimeSpan, format: str = "c", _provider: Any | None = None) -> str:
if format not in ["c", "g", "G"]:
raise ValueError("Custom formats are not supported")

Expand All @@ -126,7 +163,7 @@ def to_string(ts: timedelta, format: str = "c", _provider: Any | None = None) ->
m = minutes(ts)
s = seconds(ts)
ms = abs(milliseconds(ts))
sign: str = "-" if ts < timedelta(0) else ""
sign: str = "-" if ts < 0 else ""

ms_str = (
""
Expand All @@ -143,9 +180,14 @@ def to_string(ts: timedelta, format: str = "c", _provider: Any | None = None) ->

__all__ = [
"create",
"to_milliseconds",
"to_string",
"total_microseconds",
"total_milliseconds",
"total_seconds",
"total_minutes",
"total_hours",
"total_days",
"from_ticks",
"from_microseconds",
"from_milliseconds",
"from_hours",
"from_minutes",
Expand Down
Loading

0 comments on commit fa287de

Please sign in to comment.