Search code examples
prologswi-prolog

Incrementing datetime by second


I'm trying to take a datestring, e.g. 2020-03-04 06:22:59.012315131 and increment it by one second so it becomes 2020-03-04 06:23:00. The ms ending part doesn't matter.

Using the date library I have been able to successfully increment the time by minutes.

:- use_module(library(date)).

get_dt(Datestring, Y, M, D, H, Mn, S, X) :-
    parse_time(Datestring, Stamp1),
    stamp_date_time(Stamp1, DateTime1, 'UTC'),
    DateTime1 = date(Y1, M1, D1, H1, Mn1, S1, _, _, _),
    Mn2 is Mn1 + X,
    date_time_stamp(date(Y1, M1, D1, H1, Mn2, S1, _, _, _), Stamp2),
    stamp_date_time(Stamp2, DateTime2, 'UTC'),
    DateTime2 = date(Y, M, D, H, Mn, S, _, _, _).

When running the following it successfully increments the time to the next hour, e.g. Hour 6 to Hour 7 and resets the Minute value from 22 to 0. This justs adds 38 to the Mn value.

?- get_dt('2020-03-04 06:22:59.012315131', Y, M, D, H, Mn, S, 38).
Y = 2020,
M = 3,
D = 4,
H = 7,
Mn = 0,
S = 59.012315034.

I'm trying to do the same thing with Seconds instead of Minutes, and to increment Second of 59 by the value of 1 to 60, so that the Minute value will increment by 1. However, when incrementing seconds by 1 so the minute has to increment as seconds is now 60, it increments Minute by 2 from 22 to 24. I can't understand why.

:- use_module(library(date)).

get_dt(Datestring, Y, M, D, H, Mn, S, X) :-
    parse_time(Datestring, Stamp1),
    stamp_date_time(Stamp1, DateTime1, 'UTC'),
    DateTime1 = date(Y1, M1, D1, H1, Mn1, S1, _, _, _),
    S2 is S1 + X,
    date_time_stamp(date(Y1, M1, D1, H1, Mn1, S2, _, _, _), Stamp2),
    stamp_date_time(Stamp2, DateTime2, 'UTC'),
    DateTime2 = date(Y, M, D, H, Mn, S, _, _, _).
?- get_dt('2020-03-04 06:22:59.012315131', Y, M, D, H, Mn, S, 1).
Y = 2020,
M = 3,
D = 4,
H = 6,
Mn = 24,
S = 0.012315034.

EDIT: This last example above should show a Mn value of 23, or I think it should anyway.

Thanks


Solution

  • Copied from Discourse

    Not sure why, but it works fine if you actually pass on the timezone info:

    :- use_module(library(date)).
    
    get_dt(Datestring, Y, M, D, H, Mn, S, X) :-
        parse_time(Datestring, Stamp1),
        stamp_date_time(Stamp1, DateTime1, 'UTC'),
        DateTime1 = date(Y1, M1, D1, H1, Mn1, S1, Off, TZ, DST),
        S2 is S1 + X,
        date_time_stamp(date(Y1, M1, D1, H1, Mn1, S2, Off, TZ, DST), Stamp2),
        stamp_date_time(Stamp2, DateTime2, 'UTC'),
        DateTime2 = date(Y, M, D, H, Mn, S, _, _, _).
    
    ?- get_dt('2020-03-04 06:22:59.012315131', Y, M, D, H, Mn, S, 1).
    Y = 2020,
    M = 3,
    D = 4,
    H = 6,
    Mn = 23,
    S = 0.012315034.
    

    Surely passing on is a good idea. I'm afraid I do not have time right now to figure out what exactly is supposed to happen if you pass variables.

    Surely if you want to compute second offsets, doing so based on the time stamp is a lot easier. The non-normalized values for the time stamp are useful if you want to change a date by a month or a year as these do not have a defined number of seconds.