Skip to content

Commit

Permalink
Implemented date.parse and date.format procedures
Browse files Browse the repository at this point in the history
Also added e2e tests for them.
  • Loading branch information
idoraban authored and Ignition committed Aug 22, 2023
1 parent 409c726 commit 6137a25
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 0 deletions.
Empty file.
6 changes: 6 additions & 0 deletions e2e/date_test/test_format1/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
query: >
CALL date.format(74976, "h", "%Y/%m/%d %H:%M:%S %Z", "Mexico/BajaNorte") YIELD formatted
RETURN formatted
output:
- formatted: "1978/07/21 17:00:00 PDT"
Empty file.
6 changes: 6 additions & 0 deletions e2e/date_test/test_format2/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
query: >
CALL date.format(74976002900, "ms", "%Y/%m/%d %H:%M:%S %Z", "Australia/Broken_Hill") YIELD formatted
RETURN formatted
output:
- formatted: "1972/05/18 04:10:02 ACST"
Empty file.
6 changes: 6 additions & 0 deletions e2e/date_test/test_format3/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
query: >
CALL date.format(7491, "d", "%Y/%m/%d %H:%M:%S %z", "Brazil/DeNoronha") YIELD formatted
RETURN formatted
output:
- formatted: "1990/07/05 22:00:00 -0200"
Empty file.
6 changes: 6 additions & 0 deletions e2e/date_test/test_parse1/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
query: >
CALL date.parse("2023/08/03 14:30:00", "h", "%Y/%m/%d %H:%M:%S", "Europe/Zagreb") YIELD parsed
RETURN parsed
output:
- parsed: 469740
Empty file.
6 changes: 6 additions & 0 deletions e2e/date_test/test_parse2/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
query: >
CALL date.parse("21 June, 2018", "d", "%d %B, %Y", "US/Samoa") YIELD parsed
RETURN parsed
output:
- parsed: 17703
Empty file.
6 changes: 6 additions & 0 deletions e2e/date_test/test_parse3/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
query: >
CALL date.parse("14-Feb-1985 01:02:03", "s", "%d-%b-%Y %H:%M:%S", "Pacific/Chatham") YIELD parsed
RETURN parsed
output:
- parsed: 477141423
124 changes: 124 additions & 0 deletions python/date.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import mgp
import pytz
import datetime

from mage.date.constants import Conversion, Epoch


def getOffset(timezone, date):
offset = pytz.timezone(timezone).utcoffset(date)
if offset.days == 1:
return (
datetime.timedelta(
minutes=offset.seconds // Conversion.SECONDS_IN_MINUTE
+ Conversion.HOURS_IN_DAY * Conversion.MINUTES_IN_HOUR
),
False,
)
elif offset.days == -1:
return (
datetime.timedelta(
minutes=Conversion.HOURS_IN_DAY * Conversion.MINUTES_IN_HOUR
- offset.seconds // Conversion.SECONDS_IN_MINUTE
),
True,
)
return (
datetime.timedelta(minutes=offset.seconds // Conversion.SECONDS_IN_MINUTE),
False,
)


@mgp.read_proc
def parse(
time: str,
unit: str = "ms",
format: str = "%Y-%m-%d %H:%M:%S",
timezone: str = "UTC",
) -> mgp.Record(parsed=int):
first_date = Epoch.UNIX_EPOCH
input_date = datetime.datetime.strptime(time, format)

if timezone not in pytz.all_timezones:
raise Exception(
"Timezone doesn't exist. Check documentation to see available timezones."
)

offset, add = getOffset(timezone, input_date)
tz_input = input_date + offset if add else input_date - offset

time_since = tz_input - first_date

if unit == "ms":
parsed = (
time_since.days
* Conversion.HOURS_IN_DAY
* Conversion.MINUTES_IN_HOUR
* Conversion.SECONDS_IN_MINUTE
* Conversion.MILLISECONDS_IN_SECOND
+ time_since.seconds * Conversion.MILLISECONDS_IN_SECOND
)
elif unit == "s":
parsed = (
time_since.days
* Conversion.HOURS_IN_DAY
* Conversion.MINUTES_IN_HOUR
* Conversion.SECONDS_IN_MINUTE
+ time_since.seconds
)
elif unit == "m":
parsed = (
time_since.days * Conversion.HOURS_IN_DAY * Conversion.MINUTES_IN_HOUR
+ time_since.seconds // Conversion.SECONDS_IN_MINUTE
)
elif unit == "h":
parsed = (
time_since.days * Conversion.HOURS_IN_DAY
+ time_since.seconds
// Conversion.SECONDS_IN_MINUTE
// Conversion.MINUTES_IN_HOUR
)
elif unit == "d":
parsed = time_since.days
else:
raise Exception(
"Unit doesn't exist. Check documentation to see available units."
)

return mgp.Record(parsed=parsed)


@mgp.read_proc
def format(
time: int,
unit: str = "ms",
format: str = "%Y-%m-%d %H:%M:%S %Z",
timezone: str = "UTC",
) -> mgp.Record(formatted=str):
first_date = Epoch.UNIX_EPOCH

if unit == "ms":
new_date = first_date + datetime.timedelta(milliseconds=time)
elif unit == "s":
new_date = first_date + datetime.timedelta(seconds=time)
elif unit == "m":
new_date = first_date + datetime.timedelta(minutes=time)
elif unit == "h":
new_date = first_date + datetime.timedelta(hours=time)
elif unit == "d":
new_date = first_date + datetime.timedelta(days=time)
else:
raise Exception(
"Unit doesn't exist. Check documentation to see available units."
)

if timezone not in pytz.all_timezones:
raise Exception(
"Timezone doesn't exist. Check documentation to see available timezones."
)
offset, subtract = getOffset(timezone, new_date)
tz_new = new_date - offset if subtract else new_date + offset

return mgp.Record(
formatted=pytz.timezone(timezone).localize(tz_new).strftime(format)
)
12 changes: 12 additions & 0 deletions python/mage/date/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import datetime


class Conversion(int):
MINUTES_IN_HOUR = 60
SECONDS_IN_MINUTE = 60
MILLISECONDS_IN_SECOND = 1000
HOURS_IN_DAY = 24


class Epoch(datetime.datetime):
UNIX_EPOCH = datetime.datetime(1970, 1, 1, 0, 0, 0)

0 comments on commit 6137a25

Please sign in to comment.