aboutsummaryrefslogtreecommitdiff
path: root/doc/ref/guile/datetime.texi
blob: d49c4adaf64b306330ccc9172171d038af31b69d (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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
@node Datetime
@section Datetime

My datetime library, with focus on date manipulation in ways sensible
for humans. So that a date-time plus one day always keep the time of
day.
For example, 26 mars 2022 10:00 plus 1 day would give 27 mars 2022
10:00, even though 25 hours have passed due to summer time starting
(in Sweden).

Note that while some of these procedures mentions timezones, almost
nothing is actually done with it.

@subsection Constants

@defvar jan
@defvarx january
@defvarx feb
@defvarx february
@defvarx mar
@defvarx mars
@defvarx apr
@defvarx april
@defvarx may
@defvarx jun
@defvarx june
@defvarx jul
@defvarx july
@defvarx aug
@defvarx august
@defvarx sep
@defvarx september
@defvarx oct
@defvarx october
@defvarx nov
@defvarx november
@defvarx dec
@defvarx december
Numeric constants for all months.
@code{@var{jan} = 1}, @code{@var{dec} = 12}.
@end defvar

@defvar sun
@defvarx sunday
@defvarx mon
@defvarx monday
@defvarx tue
@defvarx tuesday
@defvarx wed
@defvarx wednesday
@defvarx thu
@defvarx thursday
@defvarx fri
@defvarx friday
@defvarx sat
@defvarx saturday
@anchor{sunday}
Numeric constants for all weekdays.
@code{@var{sunday} = 0}, @code{@var{saturday} = 6}.
@end defvar

@subsection Parameters and Configuration

@deftp {parameter} week-start
@anchor{week-start}
Which weekday should be considered the first. Used for calculating
week numbers, the start dates of week, and is available for UI-code
and the like which wants it.
@end deftp

@deftp {config} week-start
Configuration item, updates @xref{week-start}.
@end deftp


@subsection Datatypes

@deftp {Immutable Record} <date> year month day
Object representing a date, without any timezone information.
Given the date 2040-03-23 (in ISO-8601 format), @var{year} = 2020,
@var{month} = 3 and @var{day} = 23.

Values higher than those usually used are possible, but not recommended.

@defun date? x
Is @var{x} a date object?
@end defun

@defun date [#:year=0] [#:month=0] [#:day=0]
Create a new date object.
@end defun

@defun year <date>
@defunx month <date>
@defunx day <date>
Fetch corresponding field from the date object.
@end defun
@end deftp

@deftp {Immutable Record} <time> hour minute second
Object representing a timestamp in a given day,
without any timezone information.
Given the time 10:20:30, @var{hour} = 10,
@var{minute} = 20 and @var{second} = 30.

Values larger than the ``regular'' are allowed, and useful since this
type is also used for time offsets.

@defun time? x
Is @var{x} a time object?
@end defun

@defun time [#:hour=0] [#:minute=0] [#:second=0]
Create a new time object.
@end defun

@defun hour <time>
@defunx minute <time>
@defunx second <time>
Fetch corresponding field from the time object.
@end defun
@end deftp


@deftp {Immutable Record} <datetime> date time tz

A collation of date and time, along with an optional timezone.
Set @code{tz = #f} if a timezone is not desired.

@defun datetime? x
Is @var{x} a datetime object?
@end defun

@defun datetime [#:date] [#:time] [#:tz] [#:year=0] [#:month=0] [#:day=0] [#:hour=0] [#:minute=0] [#:second=0]
Creates a new <datetime>. If @var{date} or @var{time} is given, those
are used. Otherwise, a date object is created from @var{year},
@var{month} and @var{day}, and time is respectively created from
@var{hour}, @var{minute} and @var{second}.
@end defun

@defun get-date
@defunx get-timezone
Note that @code{get-time} doesn't exists.
@end defun
@end deftp


@subsection Reader Extensions

This module registers reader extensions on @code{#0}, @code{#1}, and
@code{#2}. These read either dates, times, or datetimes; using @code{string->date/-time}.

@c @subsection CTIME

@c These procedures are for interfacing with C's time procedures, see CTIME(3).

@c The datetime<->tm procedures are internal, since they are slightly
@c unstable (see comments in code).
@c They are thereby not documented.
@c @defun datetime->tm datetime
@c Convert a @code{<datetime>} object to a @code{struct tm}, encoded in a
@c scheme vector.
@c @end defun
@c 
@c @defun tm->datetime tm
@c Converts a @code{struct tm}, as returned from @code{datetime->tm} back
@c into a @code{<datetime>} object.
@c @end defun

@subsection Procedures

@defun datetime->unix-time datetime
Converts @var{datetime} to an integer representing its unix time.
@end defun

@defun unix-time->datetime n
Converts a given unix timestamp to a datetime object.
Currently forces the timezone to be UTC.
@end defun

@defun current-datetime
Return a datetime object of the current date and time.
Currently always returns it in UTC.
@end defun

@defun current-date
Get the date component from a call to @code{current-datetime}.
@end defun


@defun get-datetime datetime
Takes a datetime in any timezone, and renormalize it to local time (as
defined by the environment variable TZ). This means that given UTC
10:00 new years day would return 11:00 new years day if ran in sweden.
@end defun


@defun as-date date/-time
@defunx as-time date/-time
Both procedures takes a <date>, <time>, or <datetime>, and return
respectively a <date> or <time> object.

@code{as-date}, when given a time will return a zeroed date object.
Vice versa for @code{as-time}.
@end defun

@defun as-datetime date/-time
Takes a <date>, <time>, or <datetime>, and returns a <datetime> object
with the same data, with the (possibly) missing date or time set to
all zeroes.
@end defun


@defun date-zero? date
@defunx time-zero? time
Checks if all components are zero.
@end defun


@defun leap-year? year
Given an integer @var{year}, return @code{#t} if it's a leap year, and
@code{#f} otherwise.
@end defun

@defun days-in-month date
Returns how many days are in the month specified by the <date> @var{date}.
Note that the day component is ignored.
@end defun

@defun days-in-year date
Returns how many days are in the year pointed to by @var{date}.
@end defun

@defun start-of-month date
Returns a <date> object equal to date, but with the day component set
to 1.
@end defun

@defun end-of-month date
Returns a <date> object equal to date, but with the day component set
to the last day of the month.

@example
(end-of-month #2020-01-10)
⇒ #2020-01-31
(end-of-month #2020-02-01)
⇒ #2020-02-29
@end example
@end defun


@defun start-of-year date
Returns a <date> object equal to date, but with the day and month
component set to 1.
@end defun

@defun date-stream date-increment start-day
Returns an @ref{(guile)SRFI-43} stream of <date> objects, starting at
@var{start-day} and stepping in increments of @var{date-increment}.
@end defun

@defun day-stream start-day
Returns a stream of each day from @var{start-day}.
@end defun

@defun month-stream start-day
Returns a stream of each months from @var{start-day}.
Day component stays the same.
@end defun

@defun week-stream start-day
Returns a stream of each week from @var{start-day}
(increments of 7 days).
@end defun

@defun time-min a b
@defunx time-max a b
@defunx date-min a b
@defunx date-max a b
@defunx datetime-min a b
@defunx datetime-max a b
Returns the smaller (or larger) of @var{a} or @var{b}.
@end defun

@defun month+ date [change=1]
@defunx month- date [change=1]
Equivalent to @code{(date+ date (date month: change))}.
@end defun

@defun week-day date
Returns an integer representing the week day of @var{date}.
@ref{sunday}
@end defun


@defun week-1-start date [week-start=(week-start)]
Returns the date which week 1 starts on, according to the (at least)
Swedish rule of week counting.
@ref{week-start}
@end defun


@defun week-number date [week-start=(week-start)]
Returns the week number of @var{date}, according to the (at least)
Swedish rule of week counting.
@ref{week-start}
@end defun

@defun date-starting-week week-number date [week-start=(week-start)]
Returns the first day of week @var{week-number}, @var{date} is used
for year information.
@ref{week-start}
@end defun


@defun week-day-name week-day [truncate-to] [#:key locale]
Returns the locale dependent name for the given week day.

@var{week-day} is a number per @ref{sunday}.
@var{truncate-to} may be a number, which limits to the first @var{n}
letters of the resulting string.
@end defun


@defun timespan-overlaps? s1-begin s1-end s2-begin s2-end
Check if the interval @var{s1-begin} to @var{s1-end} overlaps with the
interval @var{s2-begin} to @var{s2-end}.
@end defun

@defun find-first-week-day week-day date
Returns the first instance of the given week-day after @var{date}.

@example
(find-first-week-day mon #2020-04-01)
⇒ #2020-04-06
(find-first-week-day mon #2020-04-10)
⇒ #2020-04-13
(find-first-week-day mon #2020-04-30)
⇒ #2020-05-04
@end example
@end defun

@defun all-wday-in-month week-day month-date
Returns instances of the given week-day in month between
month-date and end of month.
@example
(all-wday-in-month mon #2020-06-01)
⇒ (#2020-06-01 #2020-06-08 #2020-06-15 #2020-06-22 #2020-06-29)
(all-wday-in-month mon #2020-06-10)
⇒ (#2020-06-15 #2020-06-22 #2020-06-29)
@end example
@end defun

@defun all-wday-in-year week-day year-date
Returns a list of all instances of @var{week-day} in @var{year-date}.
@end defun

@defun add-day date
@defunx remove-day date
@code{@var{date} ± (date day: 1)}
@end defun

@defun in-date-range? start-date end-date → date → boolean
Returns a predicate procedure, which checks if a given date is between
@var{start-date} and @var{end-date}.
@end defun

@defun weekday-list [week-start=(week-start)]
Returns a list of the seven week days, with @var{week-start}
as the beginning of the week.
@end defun


@defun start-of-week d [week-start=(week-start)]
@defunx end-of-week d [week-start=(week-start)]
Returns the date the week containing @var{d} started or ended.
@end defun


@defun month-days date [week-start=(week-start)]
Given a month and and which day the week starts on,
returns three lists, which are:
The days leading up to the current month, but share a week
The days in the current month
The days after the current month, but which shares a week.

@example
      mars 2020
må ti on to fr lö sö
                   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
@end example
@lisp
(month-days #2020-03-01 mon)
; ⇒ (2020-02-24 ... 2020-02-29)
; ⇒ (2020-03-01 ... 2020-03-31)
; ⇒ (2020-04-01 ... 2020-04-05)
@end lisp
Ignores day component of @var{date}.
@end defun


@defun days-in-interval start-date end-date
The amount of days in the given interval, including both endpoints.
@end defun


@defun year-day date
Day from start of the year, so 1 feb would be day 32.
Also known as Julian day.
@end defun


@defun time->decimal-hour time
Convert @var{time} to a decimal value, so 10:30 would become 10.5.
@end defun

@defun datetime->decimal-hour dt [start-date]
Similar to @code{time->decimal-hour}, but also looks at the date component.

@var{start-date} is required if either the month of year component of
@var{dt} is non-zero (since months and years have a variable number of hours).
@end defun

@defun date-range start end [increment=(date day: 1)]
Returns a list of all dates from start to end.
Both inclusive
@end defun

@defun locale-month
@defunx locale-month-short
These are direct re-exports from (ice-9 i18n)

@xref{Accessing Locale Information,,,guile}.
@end defun

@defun date= args ...
@defunx date=? args ...
@defunx date< args ...
@defunx date<? args ...
@defunx date> args ...
@defunx date>? args ...
@defunx date<= args ...
@defunx date<=? args ...
@defunx date>= args ...
@defunx date>=? args ...
Checks if all date arguments satisfy the predicate.
@end defun

@defun time= args ...
@defunx time=? args ...
@defunx time< a b
@defunx time<? a b
@defunx time> a b
@defunx time>? a b
@defunx time<= a b
@defunx time<=? a b
@defunx time>= a b
@defunx time>=? a b
Checks if all time arguments satisfy the predicate.
@end defun

@defun datetime= args ...
@defunx datetime=? args ...
@defunx datetime< a b
@defunx datetime<? a b
@defunx datetime> a b
@defunx datetime>? a b
@defunx datetime<= a b
@defunx datetime<=? a b
@defunx datetime>= a b
@defunx datetime>=? a b
Check if all datetime arguments satisfy the predicate.
The timezone field is ignored.
@end defun

@defun date/-time< a b
@defunx date/-time<? a b
@defunx date/-time> a b
@defunx date/-time>? a b
@defunx date/-time<= a b
@defunx date/-time<=? a b
@defunx date/-time>= a b
@defunx date/-time>=? a b
Equivalent to the @code{datetime*} versions, but wraps its arguments
in @code{as-datetime}.
@end defun

@subsection Arithmetic

While only one date (and one time) type is available, it really should
be seen as two. Absolute dates, such as the fourth of november,
2022. The other type are intervals, such as 3 years, 4 months and 2 days.

A ``type mismatch'' might therefore lead to some confounding results.
@example
(date- #2020-01-01 #2020-01-01)
⇒ #00-1-11-31
(date-difference #2020-01-01 #2020-01-01)
⇒ #0000-00-00
@end example

@defun date+ base rest ...
@defunx date- base rest ...
Add or remove each difference from base.
@end defun

@defun date-difference end start
Returns difference between the two dates, in years, months, and days.
In such a way that

@lisp
(date= (date+ start (date-difference end start)))
@end lisp
@end defun

@defun time+ base rest ...
@defunx time- base rest ...
Adds (or subtracts) each difference from the base, and returns two
values. The sum, and how many midnight's have passed.

@lisp
(time+ #22:00:00 (time hour: 4))
⇒ #02:00:00
⇒ 1
@end lisp
@end defun

@defun datetime+ base change
@defunx datetime- base change
@end defun

@defun datetime-difference end start
@end defun

@subsection Parsing and Formatting

@defun datetime->string datetime [fmt=''~Y-~m-~dT~H:~M:~S''] [#:allow-unknown?]

Formats @var{datetime} into a string.
The function will throw an error when encountering an unknown format
specifier, unless @var{#:allow-unknown} is true.

@table @samp
@item ~~
A literal tilde (~).
@item ~H
Hour, left padded with zeroes to length 2.
@item ~k
Like @samp{~H}, but padded with spaces.
@item ~M
Minute, left padded with zeroes to length 2.
@item ~S
Seconds, left padded with zeroes to length 2.
@item ~Y
Year, left padded with zeroes to length 4;
@item ~m
Month number, left padded with zeroes to length 2.
@item ~d
Day in month, left padded with zeroes to length 2.
@item ~s
Epoch time, per UNIX.
@item ~e
Same as @samp{~d}, but padded with spaces.
@item ~1
Shorthand for @samp{~Y-~m-~d}.
@item ~3
Shorthand for @samp{~H:~M:~S}.
@item ~A
Locale week day name.
@item ~a
Locale week day name, truncated to 3 characters.
@item ~b
Locale month name, truncated.
@item ~B
Locale month name, in full.
@item ~Z
@samp{Z} if the timezone is @samp{UTC}. Nothing otherwise.
@end table
@end defun

@defun date->string date [fmt=''~Y-~m-~d''] [#:allow-unknown?]
@defunx time->string date [fmt=''~H:~M:~S''] [#:allow-unknown?]
Simple wrappers around @code{datetime->string}, which works directly
on date or time objects.
@end defun


@defun string->datetime str [fmt=''~Y-~m-~dT~H:~M:~S~Z''] [locale=%global-locale]
Attempts to parse @var{str} as a datetime, according to the ruleset @var{fmt}.
An invalid or unparsable string will throw an error.

Each token in @var{fmt} informs the parser what the next expected
token in @var{str} is. If a binding rule is parsed multiple times,
then the last one is used for the resulting object. For example,
@example
(string->datetime "10:20" "~H:~H")
⇒ (datetime hour: 20)
@end example

spaces are literal, there is no way to match an arbitrary number of
whitespace characters

@table @samp
@item ~~
Next token is a literal tilde.

@item ~Z
If next token is a literal @samp{Z} then the resulting timezone is set
to @samp{UTC}, otherwise does nothing.

@item ~p
The next token is an AM/PM indicator, matched by the regex
@code{^([AaPp])[.]?[Mm][.]?}. A valid token will reinterpret the last
hour indicator as 12-hour time (instead of 24 hour time), regardless
if its before or after this token.

@item ~b
@itemx ~B
@itemx ~h
Parses a month by name, just as @code{parse-month}.

@item ~H
@itemx ~M
@itemx ~S
@itemx ~m
@itemx ~d
Parses up to two digits, but possibly less if a non-digit appears in
the string. Then stores the resulting value in either the hour,
minute, second, month, or day slot of the resulting object.

This double function allows both dates without delimiters, such as
``0102'' to be correctly parsed, but also more free form formats, such
as ``1 jan''.

@item ~Y
Equivalent to @samp{~H}, but reads up to 4 digits, and stores the
result in the year field.
@end table
@end defun


@defun parse-month str [locale=%global-locale]
Returns the first month whose name has @var{str} as its prefix.
The result will be on the interval [1, 12], or -1 if no month matched.
@end defun


@defun string->time str [fmt=''~H:~M:~S''] [locale=%global-locale]
@defunx string->date str [fmt=''~Y-~m-~d''] [locale=%global-locale]
Wrappers around @code{string->datetime}, but only returning the time
or date component.
@end defun


@defun string->date/-time string
Parses string as an ISO-8601 string. Checks for the existence of
@code{T}, @code{:}, or @code{-} to determine if it's a datetime, time
or date.
@end defun

@defun parse-ics-date str
@defunx parse-ics-time str
@defunx parse-ics-datetime str [zone]
Parses dates per RFC5545.
@end defun

@defun parse-iso-date str
@defunx parse-iso-time str
@defunx parse-iso-datetime str
Parses (the well known subset) of ISO-compatible dates.
@end defun

@defun parse-freeform-date str
Currently an alias for parse-iso-datetime, but should preferably be extended.
@end defun