summaryrefslogtreecommitdiff
path: root/notes/misclibs/datetime.lh
blob: cc5c77c42bc82bd6c920836c930e8119e418b273 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286


# TODO split these into locale-unspecific and locale-specific formats?
# TODO should human readable timezones be in Europe/Paris style or CEST style (the latter includes DST, and is unambiguous during the DST switch, but are the codes standardized?)
type DateTimeFormat = enum (
    # Standardized, international, formats. These use leading zeros and 24 hour time
    ISOTime,       # HH:MM
    ISOTimeSec,    # HH:MM:SS
    ISOTimeTZ,     # HH:MMZZZZ
    ISOTimeSecTZ,  # HH:MM:SSZZZZ
    ISOHour,       # HH
    ISOMinute,     # MM
    ISOSecond,     # SS
    ISOHundredth,  # zero-padded
    ISOMillisecond,# zero-padded
    ISONanosecond, # zero-padded
    ISOTZ          # ZZZZ  - FIXME: is this numeric or a character code? and shouldn't we have both?
    ISODate,       # YYYY-MM-DD
    ISOYearMonth,  # YYYY-MM
    ISOYear,       # YYYY
    ISOMonth,      # MM
    ISODate,       # DD
    ISODateTime,   # YYYY-MM-DDTHH:MM, see also RFCDateTime and IntlDateTime which has a space and may be more suitable for human readable dates
    ISODateTimeSec,# YYYY-MM-DDTHH:MM:SS
    ISODateTimeTZ, # YYYY-MM-DDTHH:MMZZZZ
    ISODateTimeSecTZ, # YYYY-MM-DDTHH:MM:SSZZZZ
    ISOYearForWeek,# YYYY (for week, may differ from ISOYear in first and last week)
    ISOWeek,       # WW
    ISOYearWeek    # YYYY-WW (using week year)
    ISOWeekDayNumber, # day in week, monday comes first (TODO is monday 0 or 1?)
    RFCDateTime,   # YYYY-MM-DD HH:MM
    RFCDateTimeSec,# YYYY-MM-DD HH:MM:SS
    RFCDateTimeTZ, # YYYY-MM-DD HH:MMZZZZ
    RFCDateTimeSecTZ, # YYYY-MM-DD HH:MM:SSZZZZ
    IntlDateTimeHumanTZ # YYYY-MM-DD HH:MM Z/Z
    IntlDateTimeHumanSecTZ # YYYY-MM-DD HH:MM:SS Z/Z
    IntlTextualDate, # 31 January 2020 (always English)
    IntlTextualDateTime, # 31 January 2020, 13:53 (always English)
    IntlTextualDateTimeSec, # 31 January 2020, 13:53:43 (always English)
    IntlTextualDateTimeTZ, # 31 January 2020, 13:53 Europe/Paris (always English)
    IntlTextualDateTimeSecTZ, # 31 January 2020, 13:53:43 Europe/Paris (always English)
    MailDateTime,  # TODO...
    UnixTimestamp, # Calendar seconds (taking leap seconds into account) since 1 jan 1970 00:00 UTC
    UnixTimestampMillis,
    UnixTimestampNanos,
    XXXTimestamp,  # Actual seconds since 1 jan 1970 00:00 UTC
    XXXTimestampMillis,
    XXXTimestampNanos,
    # Common formats.
    # Note that some locales have eras and non-georgian dates.
    # For these IF the era or non-georgian format is the most common one, then it will be returned.
    # There may also be multiple locales for a region, like one with eras and one without.
    Time,         # Short time, e.g. 23:59 for 24 hour locales or 11:59 PM for 12 hour AM/PM locales
    TimeForce24,  # Short time. Force 24 hou, regardless of locale settings
    TinyDate,     # Compact date, may use 2 digit year, e.g. YY-MM-DD and may exclude era. May be the same as ShortDate.
    ShortDate,    # Short date format, usually numeric with 4 digit year
    LongDate,     # Long date format, usually in text format, but may be numeric and may be the same as ShortDate
    # Combined formats
    TinyDateTime, # Time and TinyDate combined. Locale decides order of time and date
    TinyDateTimeForce24,
    ShortDate,
    ShortDateForce24,
    LongDate,
    LongDateForce24,
    NumericMonthDate, # numeric month+date format (e.g. D/M or M/D). If none exists in the locale, it will use a textual format, and if that does not exist, a TinyDate.
    TextualMonthDate, # textual month+date format (e.g. 31 december). If nont exists in the locale, it will use a numeric format, and if that does not exist, a TinyDate.
    # Locale specific date/time components
    LocaleHourMayBe12Hour,
    LocaleAMPM, # Empty string for 24 hour locales
    LocaleMinute,
    LocaleSecond,
    LocaleTimeZone,
    # Locale specific year+week. Note that weeks might not be used in all locales (or not commonly used)
    LocaleYearWeek, # Locale specific way of representing year and week. If not applicable to the locale, it is an ISO year and week
    LocaleWeek, # Locale specific way of representing week. If not applicable to the locale, it is an ISO week
    # These are easy to use incorrectly. Should we have them?
    LocaleGeorgianYearPrefix, # e.g. a symbol written before the year, like in Chinese
    LocaleGeorgianYearPostfix,
    LocaleGeorgianYear,
    LocaleGeorgianMonthPrefix,
    LocaleGeorgianMonthPostfix,
    LocaleGeorgianMonth, # may use english name if not applicable to the locale. may be numeric
    LocaleGeorgianDayPrefix,
    LocaleGeorgianDayPostfix,
    LocaleGeorgianDay,
    # These are easy to use incorrectly. Should we have them?
    Level1, # if applicable, or empty string
    Level2, # year in era, or simply "the" year if locale does not use eras
    Level3, # month typically
    Level4, # day typically
    Level5, # may be some kind of divison of the day, like AM/PM, or empty string. More than 2 "day segments" may exist.
    Level6, # hour, or similar, in division of day
    Level7, # minute, or similar, in division of day
    Level8, # second, or similar, in division of day
    Level9, # locale-specific division of level 8. resolution depends on the locale
)

typedef enum DateDeltaFormat = (
    # Textual formats, e.g. "3 months 2 days 16 hours"
    # smallest granularity is 1 second for these.
    TextualTiny,   # usually one component
    TextualShort,  # usually two components
    TextualMedium, # usually three components
    TextualFull,   # possibly all components
    TextualMinuteTiny,   # usually one component, < 60 seconds becomes "now"
    TextualMinuteShort,  # usually two components
    TextualMinuteMedium, # usually three components
    TextualMinuteFull,   # possibly all components
)

typedef enum DateRangeFormat = (
    NumericMonthDate,  # date granularity, do not include year (e.g. "30-31/12" for sv-SE, "12/30-31" for explicit en-US, but TinyDate for "default locale"). Falls back to a textual date and/or a range of TinyDates
    NumericYearMonthDate, # date granularity, numeric format is preferred.
    TextualMonthDate,
    TextualYearMonthDate,
)


func utcdate_string(enum DateTimeFormat format, Date date) alloc StringBuffer
func localdate_string(enum DateTimeFormat format, Date date) alloc StringBuffer
func datedelta_string(enum DateDeltaFormat format, Date date) alloc StringBuffer
func utcdaterange_string(enum DateRangeFormat format, Date from, Date to, bool from_inclusive, bool to_inclusive) alloc StringBuffer
func localdaterange_string(enum DateRangeFormat format, Date from, Date to, bool from_inclusive, bool to_inclusive) alloc StringBuffer

# A word on the default locale:
# The default locale uses US-English language, but since only
# English-speaking countries, mainland China and a few more countries use
# the 12 hour AM/PM system, the default date/time format is as follows:
# - 24 hour time
# - English names for months and weekdays
# - Georgian calendar
# - Textual date format: 31 December 2020
# - Numeric date format: 2020-12-31
# - Tiny Date: 2020-12-31
# - Short date+month: 31 December (always textual)
# - ISO week numbers
# - RFC date for combined date-time


# needs split in locale dependent/independent
type CurrencyFormat = (
    Best,      # Include decimals (e.g. cents) only if non-zero, OR if always included in locale
    BestCCode, # Like "Best", but include 3-letter currency code, e.g. "USD 12.50" or "125 SEK"
    Full,      # Always include decimals (e.g. cents)
    FullCCode, # Like "Full", but include 3-letter currency code, e.g. "USD 12.50" or "125,00 SEK"
    BestWithUnit, # Currency format with unit. E.g. "$12.50", "£10", "11€", "125 kr". May fall back to "Best" (and always will if the currency is not used in the locale). Locales may have alternative currencies, aside from the most common or official one.
    FullWithUnit,
)
# XXX long type?
func currency_string(enum CurrencyFormat format, long whole, long decimals, ref String format) alloc StringBuffer


# needs split in locale dependent/independent
type LengthFormat = enum (
    AnyMetric,
    Meters,
    Kilometers,
    LocaleTiny,    # mm / inches+fractions
    LocaleSmall,   # cm / inches
    LocaleMedium,  # meters / feet
    LocaleLarge,   # km / miles
)
func length_string(enum LengthFormat format, long meters, long nanometers) alloc StringBuffer


type VolumeFormat ...
type AreaFormat ...
type SoundLevelFormat ...
type LightFormat ...
type WeightFormat = enum (
    KG,
    Gram,
    Milligram,
    MetricTon,
    LocaleLikeKG,
    LocaleLikeGram,
    LocaleLikeMilligram,
    LocaleLikeMetricTon,
)

type SpeedFormat = enum (
    MS,  # m/s
    KMH, # km/h
    Generic, # usually m/s
    Wind,    # m/s
    GenericTravelSpeed, # usually km/h or mph
    # maybe... but since SeaTravel speed unit is too much person dependent, we should perhaps not have these below?
    LandTravel, # usually km/h or mph
    SeaTravel,  # probably km/h or knots... but this is a bit too much person dependent (both may be used)
    AirTravel,  # usually km/h or mph
)
type EnergyFormat = enum ( # maybe?
    Electricity, # typically kWh
    HumanOutput,        # may be kcal, kWh, Joule... but this is more person dependent, I would use kWh but mostly in my country we use kcal.
    Food,               # like above (but this is "input energy")
)

type NumberFormat = enum (
    # TODO thousands separators
    RomanInteger,           # Always decimal
    HexadecimalInteger,     # Always hexadecimal
    LocaleInteger,          # Whatever symbols the locale uses for numbers
    LocaleRomanFraction,    # Like 1.23 or 1,23. Always
    LocaleFraction,         # Whatever symbols the locale uses for numbers
)

#type Layout = enum (
#    
#)

type PaperSize = enum (
    A4,
    USLetter,
    # TODO...
)

type TextDirection = enum (
    LeftToRight,
    RightToLeft,
)

# should we also have options for bike brake level side etc? or too much stupid stuff that few people will use?
type TrafficSide = enum (
    Left,
    Right,
)

func get_papersize(...) returns enum PaperSize
func get_text_direction(...) returns enum TextDirection
func get_traffic_side(...) returns enum TrafficSide


type AddressLineType = enum (
    Fullname,
    VillageMasterName,
    NumberThenRoad,
    RoadThenNumber,
    RoadThenNumberOptionallyApartment,
    CareOf,
    BlockIdentifier,
    PostalCode,
    PostalCodeAndAreaName,
    PostalAreaName,
    ProvinceName,
    StateName,
    CountryName,
    # ...
)

func get_address_line(..., int i) return AddressLineType


type NameOrder = enum (
    FirstLast,
    FirstUppercaseLast,
    LastFirst,
    UppercaseLastFirst,
    # ...
)

func get_name_format(...) return enum NameOrder

type NameFormat = enum (
    Initials,
)
# This is really tricky... 
func format_name(
    int numFirstNames
    ref String[numFirstNames] first,
    int givenIndex,
    ref String englishMiddle, # this is an additional first name
    int numLastNames,
    ref [numLastNames]String last,
    ref String [numLastNames]lastPrefixes,
    enum NameFormat) alloc StringBuffer

type NameType = enum (
    Title,
    OnlyName,           # No firstname/lastname distinction exists. This is the only name.
    GivenName,
    SecondaryFirstName, # common in Nordic countries, may come before or after the given name. May be omitted in display.
    EnglishMiddleName,  # common in English-speaking countries, usually written as an initial. May be omitted in display.
    Nickname,
    SecondaryLastName,  # an additional last name, not passed on to children. Common in Nordic countries. Should be treated like a LastName.
    LastName,           # a last name.
    # ...
)