Skip to content

Commit cbabc5b

Browse files
committed
Globals for zoned date times
1 parent 4feb45a commit cbabc5b

File tree

6 files changed

+80
-47
lines changed

6 files changed

+80
-47
lines changed

harness/test/044_time.eu

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ time: cal.now."{h:%02d}:{m:%02d}:{s:%02d}"
33
tests: {
44
α: cal.now.y > 2000 //= true
55
β: cal.now.s < 62 //= true
6+
γ: cal.zdt(2019, 12, 1, 11, 23, 77, "+0400") cal.fields (.h) //= 11
7+
δ: cal.datetime({y: 2019 m: 11 d: 21}) cal.fields (.d) //= 21
8+
ε: cal.datetime({h: 12 M: 12 s: 12}) cal.fields (."{h:%02d}!{M:%02d}") //= "12!12"
69
}
710

811
RESULT: tests values all-true? then(:PASS, :FAIL)

harness/test/x044_date_times.eu

-37
This file was deleted.

lib/prelude.eu

+24-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# -*- mode: conf -*-
2-
31
# Eucalypt standard prelude
42

53
##
@@ -763,7 +761,31 @@ cal: {
763761
ifields: block ∘__IFIELDS
764762

765763
now: io.epoch-time ifields
764+
766765
epoch: 0 ifields
766+
767+
` "Intrinsics for working with unwrapped zoned date times"
768+
Γ: {
769+
zdt: __ZDT
770+
wrap: '__ZDT.WRAP'
771+
unwrap: '__ZDT.UNWRAP'
772+
fields: '__ZDT.FIELDS'
773+
}
774+
775+
` "`cal.zdt(y, m, d, h, M, s, Z)` - create zoned date time from datetime components and timezone string (e.g. '+0100')"
776+
zdt(y, m, d, h, M, s, Z): Γ.zdt(y, m, d, h, M, s, Z) Γ.wrap
777+
778+
` "`cal.time(b)` - convert block of time fields to time (with 0 / UTC defaults)"
779+
datetime(b): zdt(b lookup-or(:y, 0),
780+
b lookup-or(:m, 0),
781+
b lookup-or(:d, 0),
782+
b lookup-or(:h, 0),
783+
b lookup-or(:M, 0),
784+
b lookup-or(:s, 0),
785+
b lookup-or(:Z, "UTC"))
786+
787+
` "cal.fields(t) - decompose a zoned date time into a block of its component fields"
788+
fields: block ∘ Γ.fields ∘ Γ.unwrap
767789
}
768790

769791

src/Eucalypt/Stg/GlobalInfo.hs

+4
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ globalRegistry =
9595
, GlobalInfo "UPPER" [Strict]
9696
, GlobalInfo "LOWER" [Strict]
9797
, GlobalInfo "IFIELDS" [Strict]
98+
, GlobalInfo "ZDT" [Strict, Strict, Strict, Strict, Strict, Strict, Strict]
99+
, GlobalInfo "ZDT.WRAP" [Strict]
100+
, GlobalInfo "ZDT.UNWRAP" [Strict]
101+
, GlobalInfo "ZDT.FIELDS" [Strict]
98102
, GlobalInfo "ALIST.MERGE" [Strict, Strict]
99103
, GlobalInfo "ALIST.PRUNE" [Strict]
100104
, GlobalInfo "ALIST.DEEPMERGE" [Strict, Strict]

src/Eucalypt/Stg/Globals/Time.hs

+29
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,20 @@ module Eucalypt.Stg.Globals.Time
1313
) where
1414

1515
import Data.Symbol
16+
import Eucalypt.Stg.Globals.Common (wrapBifStrict)
17+
import Eucalypt.Stg.GlobalInfo (gref)
18+
import Eucalypt.Stg.Native (Native(..))
1619
import Eucalypt.Stg.Syn
1720
import Eucalypt.Stg.Intrinsics (intrinsicIndex)
21+
import Eucalypt.Stg.Tags
1822

1923
globals :: [(Symbol, LambdaForm)]
2024
globals =
2125
[ ("IFIELDS", euIFields)
26+
, ("ZDT", euZdt)
27+
, ("ZDT.WRAP", euZdtWrap)
28+
, ("ZDT.UNWRAP", euZdtUnwrap)
29+
, ("ZDT.FIELDS", euZdtFields)
2230
]
2331

2432
euIFields :: LambdaForm
@@ -27,3 +35,24 @@ euIFields =
2735
ann_ "__IFIELDS" 0 $
2836
force_ (Atom (L 0)) $
2937
appbif_ (intrinsicIndex "IFIELDS") [L 1]
38+
39+
40+
-- | __ZDT(y, m, d, h, M, s, Z)
41+
euZdt :: LambdaForm
42+
euZdt = wrapBifStrict "ZDT"
43+
44+
-- | __ZDT.WRAP(zdt)
45+
euZdtWrap :: LambdaForm
46+
euZdtWrap = lam_ 0 1 $ ann_ "ZDT.WRAP" 0 $ appcon_ stgZDT [L 0]
47+
48+
-- | __ZDT.UNWRAP(zdt)
49+
euZdtUnwrap :: LambdaForm
50+
euZdtUnwrap =
51+
lam_ 0 1 $
52+
ann_ "ZDT.UNWRAP" 0 $
53+
casedef_ (Atom (L 0)) [(stgZDT, (1, atom_ (L 1)))] $
54+
appfn_ (gref "PANIC") [V $ NativeString "Expected zoned date time"]
55+
56+
-- | __ZDT.FIELDS(zdt)
57+
euZdtFields :: LambdaForm
58+
euZdtFields = wrapBifStrict "ZDT.FIELDS"

src/Eucalypt/Stg/Intrinsics/Time.hs

+20-8
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,23 @@ module Eucalypt.Stg.Intrinsics.Time
1313
, toZonedDateTime
1414
) where
1515

16-
import Eucalypt.Stg.Error
17-
import Eucalypt.Stg.IntrinsicInfo
18-
import Eucalypt.Stg.Intrinsics.Common (invoke, returnList, returnDynamic)
19-
import Eucalypt.Stg.Native
20-
import Eucalypt.Stg.Machine
16+
import Data.Dynamic
2117
import Data.Scientific
2218
import Data.Time.Calendar
2319
import Data.Time.Clock.POSIX
2420
import Data.Time.LocalTime
25-
import Text.Regex.PCRE.Heavy (scan, re)
21+
import Eucalypt.Stg.Error
22+
import Eucalypt.Stg.IntrinsicInfo
23+
import Eucalypt.Stg.Intrinsics.Common (cast, invoke, returnDynamic, returnList)
24+
import Eucalypt.Stg.Machine
25+
import Eucalypt.Stg.Native
26+
import Text.Regex.PCRE.Heavy (re, scan)
2627

2728
intrinsics :: [IntrinsicInfo]
2829
intrinsics =
2930
[ IntrinsicInfo "IFIELDS" 1 (invoke instantToUTCFields)
3031
, IntrinsicInfo "ZDT" 7 (invoke toZonedDateTime)
32+
, IntrinsicInfo "ZDT.FIELDS" 1 (invoke zdtFields)
3133
]
3234

3335

@@ -38,21 +40,23 @@ instantToUTCFields s d =
3840
z = utcToZonedTime utc u
3941
in returnList s $ zonedDateTimeFields z
4042

43+
-- | Represent a 'ZonedTime' as its component fields
4144
zonedDateTimeFields :: ZonedTime -> [(Native, Native)]
4245
zonedDateTimeFields ZonedTime {..} =
4346
let LocalTime {..} = zonedTimeToLocalTime
4447
tz = timeZoneOffsetString zonedTimeZone
4548
(year, month, day) = toGregorian localDay
4649
TimeOfDay {..} = localTimeOfDay
4750
in [ (NativeSymbol "y", NativeNumber $ fromIntegral year)
48-
, (NativeSymbol "M", NativeNumber $ fromIntegral month)
51+
, (NativeSymbol "m", NativeNumber $ fromIntegral month)
4952
, (NativeSymbol "d", NativeNumber $ fromIntegral day)
5053
, (NativeSymbol "h", NativeNumber $ fromIntegral todHour)
51-
, (NativeSymbol "m", NativeNumber $ fromIntegral todMin)
54+
, (NativeSymbol "M", NativeNumber $ fromIntegral todMin)
5255
, (NativeSymbol "s", NativeNumber $ fromRational $ toRational todSec)
5356
, (NativeSymbol "Z", NativeString tz)
5457
]
5558

59+
-- | Parse a time zone string into a 'TimeZone', supports numeric or "UTC"
5660
timeZoneFromString :: MachineState -> String -> IO TimeZone
5761
timeZoneFromString _ "UTC" = return utc
5862
timeZoneFromString _ "" = return utc
@@ -68,6 +72,7 @@ timeZoneFromString ms s =
6872
in return $ minutesToTimeZone $ sig * (60 * h + m)
6973
_ -> throwIn ms $ InvalidArgument "Time zone was not valid"
7074

75+
-- | Create a raw zoned date time from its components
7176
toZonedDateTime ::
7277
MachineState
7378
-> Scientific
@@ -87,3 +92,10 @@ toZonedDateTime ms y m d h mins s tz =
8792
dtz <- timeZoneFromString ms tz
8893
returnDynamic ms $ ZonedTime locTime dtz
8994
_ -> throwIn ms $ InvalidArgument "Time field was invalid"
95+
96+
-- | Split up a raw zoned date time into its components (as k-v pairs
97+
-- for populating a block).
98+
zdtFields :: MachineState -> Dynamic -> IO MachineState
99+
zdtFields ms zdtDyn = do
100+
zdt <- cast ms zdtDyn
101+
returnList ms $ zonedDateTimeFields zdt

0 commit comments

Comments
 (0)