QB64.org Forum

Active Forums => Programs => Topic started by: SMcNeill on August 20, 2019, 12:55:30 am

Title: Function Timestamp
Post by: SMcNeill on August 20, 2019, 12:55:30 am
Code: QB64: [Select]
  1.     _LIMIT 10
  2.     LOCATE 1, 1
  3.     Countdown## = TimeStamp("01-01-2020", 0) - TimeStamp(DATE$, TIMER)
  4.     PRINT USING "###,###,###,###.### seconds till Jan 01, 2020"; Countdown##
  5. LOOP UNTIL Countdown## <= 0
  6. PRINT "HAPPY NEW YEARS!!!!"
  7.  
  8. FUNCTION TimeStamp## (d$, t##) 'date and timer
  9.     'Based on Unix Epoch time, which starts at year 1970.
  10.     'Minor fixes to leap year logic by Bplus.  Many thanks!
  11.     l = INSTR(d$, "-")
  12.     l1 = INSTR(l + 1, d$, "-")
  13.     m = VAL(LEFT$(d$, l))
  14.     d = VAL(MID$(d$, l + 1))
  15.     y = VAL(MID$(d$, l1 + 1)) - 1970
  16.     FOR i = 1 TO m
  17.         SELECT CASE i 'Add the number of days for each previous month passed
  18.             CASE 1: d = d 'January doestn't have any carry over days.
  19.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  20.             CASE 3: d = d + 28
  21.             CASE 5, 7, 10, 12: d = d + 30
  22.         END SELECT
  23.     NEXT
  24.     FOR i = 1 TO y
  25.         d = d + 365
  26.     NEXT
  27.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards.
  28.         d = d + 1 'add an extra day for leap year every 4 years, starting in 1970
  29.     NEXT
  30.     IF y > 30 THEN d = d - 1 'for year 2000, which wasn't a leap year.
  31.     IF m > 2 AND (y MOD 4 = 2) THEN d = d + 1 'fix for leap year, for the current year.
  32.     s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  33.     TimeStamp## = (s~&& + t##)

Function gives a timestamp based on Unix Epoch Time, when we give it a date a time.  Simple enough, and thanks go to Bplus for helping catch a logic error in the leap year calculations. 
Title: Re: Function Timestamp
Post by: STxAxTIC on August 20, 2019, 06:21:44 am
Thanks for making a new thread about this 'cause my time is so limited I got scared of losing this in the next few days - and the Librarian has even less time than *me*, so thanks again!

I can see that this code should replace the existing code in the Toolbox, no problem... But without studying the issue at all, I have a naive question - why did the function pass the test that led to the (obligatory) screenshot? Adjusting for local time it seemed correct - even when compared to the freebasic timecore and the one i translated for sxript. We all agreed on that test. Was the bug deep enough that only certain dates would trigger it? (Sorry, didn't read into this at all yet.)
Title: Re: Function Timestamp
Post by: SMcNeill on August 20, 2019, 06:37:40 am
Code: [Select]

FUNCTION ExtendedTimer##
    d$ = DATE$
    l = INSTR(d$, "-")
    l1 = INSTR(l + 1, d$, "-")
    m = VAL(LEFT$(d$, l))
    d = VAL(MID$(d$, l + 1))
    y = VAL(MID$(d$, l1 + 1)) - 1970
    FOR i = 1 TO m
        SELECT CASE i 'Add the number of days for each previous month passed
            CASE 1: d = d 'January doestn't have any carry over days.
            CASE 2, 4, 6, 8, 9, 11: d = d + 31
            CASE 3: d = d + 28
            CASE 5, 7, 10, 12: d = d + 30
        END SELECT
    NEXT
    FOR i = 1 TO y
        d = d + 365
    NEXT
    FOR i = 2 TO y STEP 4
        IF m > 2 THEN d = d + 1 'add an extra day for leap year every 4 years, starting in 1970
    NEXT
    d = d - 1 'for year 2000
    s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
    ExtendedTimer## = (s~&& + TIMER)
END FUNCTION
 

The glitch was in this little line of code:
IF m > 2 THEN d = d + 1 'add an extra day for leap year every 4 years, starting in 1970

So if January and February, we didn’t add a day for each leap year...

The fix is as in the first post above; let the loop go to Year - 1 (don’t check the current year yet), and simply add one for each leap year.  Then check to see if the current year is leap year, and if so, is it after februrary where we need to count that extra day.

Note:  TimeStamp and ExtendedTimer are very similar functions, but slightly different,  TimeStamp lets you specify a time and date, creating a UET value for that moment; ExtendedTimer works exclusively with your current date and time, as a replacement for the TIMER command.



Corrected version of ExtendedTimer is as follows:

Code: QB64: [Select]
  1. SHELL "https://www.epochconverter.com/"
  2.     CLS
  3.     PRINT TIMER, INT(ExtendedTimer)
  4.     PRINT "Compare to the time at https://www.epochconverter.com/"
  5.     _DISPLAY
  6.     _LIMIT 10
  7.  
  8. FUNCTION ExtendedTimer##
  9.     d$ = DATE$
  10.     l = INSTR(d$, "-")
  11.     l1 = INSTR(l + 1, d$, "-")
  12.     m = VAL(LEFT$(d$, l))
  13.     d = VAL(MID$(d$, l + 1))
  14.     y = VAL(MID$(d$, l1 + 1)) - 1970
  15.     FOR i = 1 TO m
  16.         SELECT CASE i 'Add the number of days for each previous month passed
  17.             CASE 1: d = d 'January doestn't have any carry over days.
  18.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  19.             CASE 3: d = d + 28
  20.             CASE 5, 7, 10, 12: d = d + 30
  21.         END SELECT
  22.     NEXT
  23.     FOR i = 1 TO y
  24.         d = d + 365
  25.     NEXT
  26.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year.
  27.         IF i <> 30 THEN d = d + 1 'add an extra day for leap year every 4 years, starting in 1970, but skip year 2000
  28.     NEXT
  29.     IF m > 2 AND (y MOD 4 = 2) THEN d = d + 1 'fix for leap year, for the current year.
  30.     s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  31.     ExtendedTimer## = (s~&& + TIMER)
  32.  

Or, for the minimalist folks out there, if they like TimeStamp, they could also have a quick version for:

Code: QB64: [Select]
  1. FUNCTION ExtendedTimer##
  2.     ExtendedTimer## = TimeStamp(DATE$, TIMER)
Title: Re: Function Timestamp
Post by: STxAxTIC on August 20, 2019, 06:46:37 am
Alright -

So bplus hinted that this bug propagated out of the Toolbox somehow - does the Extended Timer code need to be updated? If it did something so wrong with leap years, then why did the screenshot check out?

Or is that code fine as-is?

Gotta fly - I won't be able to hit this again for 12 hours so...
Title: Re: Function Timestamp
Post by: SMcNeill on August 20, 2019, 06:54:18 am
Alright -

So bplus hinted that this bug propagated out of the Toolbox somehow - does the Extended Timer code need to be updated? If it did something so wrong with leap years, then why did the screenshot check out?

Or is that code fine as-is?

Gotta fly - I won't be able to hit this again for 12 hours so...

The screenshot checks out because we're currently past the 2nd month...

IF m > 2 THEN d = d + 1   ...  We didn't need that IF check in there; we needed one after for the current year only.

Change is to replace:
Code: [Select]
    FOR i = 2 TO y STEP 4
        IF m > 2 THEN d = d + 1 'add an extra day for leap year every 4 years, starting in 1970
    NEXT
    d = d - 1 'for year 2000

With:
Code: [Select]
    FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year.
        IF i <> 30 THEN d = d + 1 'add an extra day for leap year every 4 years, starting in 1970, but skip year 2000
    NEXT
    IF m > 2 AND (y MOD 4 = 2) THEN d = d + 1 'fix for leap year, for the current year.

As long as your current month was > 2, the existing code worked out right.  You just suddenly lost out on a bunch of leap days when Jan/Feb rolled around, to gain them all back once we were March again.  ;)
Title: Re: Function Timestamp
Post by: bplus on August 20, 2019, 09:51:41 am
Steve, maybe you mean if i <> 30 for this part:
Code: QB64: [Select]
  1.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year.
  2.         'IF i <> 30....
  3.         IF y <> 30 THEN d = d + 1 'add an extra day for leap year every 4 years, starting in 1970, but skip year 2000
  4.     NEXT
  5.  

This could be replaced by: d = d + y * 365  ' y or y -1 ?????????? OK y I think
Code: QB64: [Select]
  1.     FOR i = 1 TO y  'y-1???? first 1970 y = 0, 1971 y = 1, 1972 y = 2  OK y not y-1
  2.         d = d + 365
  3.     NEXT
  4.  

Update:
but now, I am wondering should't this be to y-1 as we count the days in y the partial year separately.
EDIT Update: No y starts at 0 not 1, so not y-1...

OK I am writing a tester for this Function. Starting at 01-01-1970, 0 time should be 0
Title: Re: Function Timestamp
Post by: bplus on August 20, 2019, 12:06:26 pm
Update: If timestamp##("01-01-1970", 0) should be 0, it is a whole day off.

This probably offsets all time##, so when compare differences in date and time will be OK but calc of absolute seconds from 01-01-1970 will be off a day = 86400 secs.
Title: Re: Function Timestamp
Post by: SMcNeill on August 20, 2019, 12:38:28 pm
Update: If timestamp##("01-01-1970", 0) should be 0, it is a whole day off.

This probably offsets all time##, so when compare differences in date and time will be OK but calc of absolute seconds from 01-01-1970 will be off a day = 86400 secs.

And, to think, we could avoid all these issues if we just used c++ to give us the solution in one line: 
Code: C++: [Select]
  1. double now = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();

There’s a page here which can be used to compare results: https://www.epochconverter.com/

Somehow, I was matching results before; how the heck did I break things so we’re off so badly now?  I’ll dig into it later this evening when my time frees up a little again.  ;)

(And I’ll probably add that single line into my repo and just make an _EXTENDEDTIMER command and use it.  I imagine it’d be much faster than doing all the calculations manually anyway.). ;)
Title: Re: Function Timestamp
Post by: bplus on August 20, 2019, 02:46:37 pm
Quote
There’s a page here which can be used to compare results: https://www.epochconverter.com/

OK it does look like 0 AM Jan 1, 1970 is suppose to be 0 at GMT:
 


So far minimal testing subtracting 1 from d, just after it is calc'd from date$. OK

Kinda makes sense to subtract a day from the date because it isn't complete yet, the fraction of it is in the time.
Title: Re: Function Timestamp
Post by: bplus on August 20, 2019, 08:46:48 pm
Alert!

 I caught another bug on day counts and I think I have worked up a fix, leap year again or rather not a leap year this time! Be right back! Still running checks with my code tester.

Good that was the last bug for day counts anyway.

The last bug was about checking for leap year for y. We forgot to consider if y is year 2000 which is NOT a leap year.

Here is my test code that tests day counts from 01-01-1970 to 01-01-2035 by comparing the day count current test date to the day count for the test date for day before, if the day count <> last day count + 1 the code stops running on the error producing date.
Code: QB64: [Select]
  1. _TITLE "Test TimeStamp##" 'b+ started 2019-08-20
  2. ' Steve's TimeStamp## even better than Toolbox tool!
  3.  
  4. d = 0: m = 1: yr = 1970
  5.     d = d + 1
  6.     IF d = 29 AND m = 2 THEN
  7.         'is it leap year
  8.         IF yr - 1970 = 30 THEN
  9.             m = 3: d = 1
  10.         ELSEIF ((yr - 1970) MOD 4 = 2) THEN
  11.             'd is ok
  12.         ELSE
  13.             m = 3: d = 1
  14.         END IF
  15.     ELSEIF d = 30 AND m = 2 THEN 'must be leap year
  16.         m = 3: d = 1
  17.     ELSEIF d = 31 THEN
  18.         IF m = 4 OR m = 6 OR m = 9 OR m = 11 THEN
  19.             m = m + 1: d = 1
  20.         END IF
  21.     ELSEIF d = 32 THEN
  22.         IF m = 12 THEN
  23.             d = 1: m = 1: yr = yr + 1
  24.         ELSE
  25.             d = 1: m = m + 1
  26.         END IF
  27.     END IF
  28.     d2$ = RIGHT$("0" + _TRIM$(STR$(m)), 2) + "-" + RIGHT$("0" + _TRIM$(STR$(d)), 2) + "-" + _TRIM$(STR$(yr))
  29.     d1$ = "01-01-1970"
  30.  
  31.     a## = TimeStamp##(d1$, 5)
  32.     b## = TimeStamp##(d2$, 5)
  33.     moda## = BmodTimeStamp##(d1$, 5)
  34.     modb## = BmodTimeStamp##(d2$, 5)
  35.  
  36.     dab& = (a## - b##) \ 1
  37.     PRINT dab&
  38.     IF dab& < 0 THEN
  39.         flagNeg = -1: dab& = -dab&
  40.     ELSE
  41.         flagNeg = 0
  42.     END IF
  43.     days% = dab& \ (86400)
  44.     dab& = dab& - days% * 86400
  45.     hours% = dab& \ 3600
  46.     dab& = dab& - hours% * 3600
  47.     minutes% = dab& \ 60
  48.     secs% = dab& - minutes% * 60
  49.  
  50.     moddab& = (moda## - modb##) \ 1
  51.  
  52.     IF moddab& < 0 THEN
  53.         modflagNeg = -1: moddab& = -moddab&
  54.     ELSE
  55.         modflagNeg = 0
  56.     END IF
  57.     moddays% = moddab& \ (86400)
  58.     moddab& = moddab& - moddays% * 86400
  59.     modhours% = moddab& \ 3600
  60.     moddab& = moddab& - modhours% * 3600
  61.     modminutes% = moddab& \ 60
  62.     modsecs% = moddab& - modminutes% * 60
  63.  
  64.     CLS
  65.     PRINT "The two dates A and B: "; d1$, d2$
  66.     PRINT
  67.     'PRINT "Updated 2019-08-20 10:58 AM if i <> 30 fix from if y <> 30"
  68.     PRINT "Steve TimeStamp## Function:"
  69.     PRINT "A##, B## TimeStamps: "; a##, b##
  70.     PRINT "Difference between A## and B##:"; days%; "days,"; hours%; "hours,"; minutes%; "minutes,"; secs%; "secs, ";
  71.     IF flagNeg THEN
  72.         PRINT "B## was later than A##"
  73.     ELSE
  74.         PRINT "A## was later than B##"
  75.     END IF
  76.  
  77.     PRINT: PRINT "B mods compare:"
  78.     PRINT "mod A##, mod B## TimeStamps: "; moda##, modb##
  79.     PRINT "Difference between mod A## and mod B##:"; moddays%; "days,"; modhours%; "hours,"; modminutes%; "minutes,"; modsecs%; "secs, ";
  80.     IF modflagNeg THEN
  81.         PRINT "mod B## was later than mod A##"
  82.     ELSE
  83.         PRINT "mod A## was later than mod B##"
  84.     END IF
  85.     PRINT
  86.     PRINT "DayCount this loop: "; moddays%, "DayCount last loop:"; lastDay%
  87.  
  88.     'INPUT "OK ... press enter "; w$
  89.     IF lastDay% <> 0 THEN
  90.         IF moddays% <> lastDay% + 1 THEN END
  91.     END IF
  92.     lastDay% = moddays%
  93.     _DISPLAY
  94.     _LIMIT 1000
  95. LOOP UNTIL yr = 2035
  96. PRINT "Done!"
  97.  
  98. ' b mod TimeStamp fixed. 2019-08-20 twiddled somemore and tested with code above
  99. FUNCTION BmodTimeStamp## (d$, t##) 'date and timer
  100.     DIM l AS INTEGER, l1 AS INTEGER, i AS INTEGER, s~&&
  101.     DIM m AS INTEGER, y AS INTEGER, d AS INTEGER
  102.     l = INSTR(d$, "-")
  103.     l1 = INSTR(l + 1, d$, "-")
  104.     m = VAL(LEFT$(d$, l))
  105.     d = VAL(MID$(d$, l + 1)) - 1 '<<<<<<<<<< the day of date is partial, so count of full days is 1 less!!
  106.     y = VAL(MID$(d$, l1 + 1)) - 1970
  107.     FOR i = 1 TO m 'count up days for year y
  108.         SELECT CASE i 'Add the number of days for each previous month passed, case 1 no change needed <<<<<<<<<<< removed case 1 line
  109.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  110.             CASE 3: d = d + 28
  111.             CASE 5, 7, 10, 12: d = d + 30
  112.         END SELECT
  113.     NEXT
  114.     d = d + 365 * y ' <<<<<<<<<<<<<<< Steve uses loop number of days before counting leap years
  115.     FOR i = 2 TO y - 1 STEP 4 ' to y-1 not y, leap years 1972, 1976, 1980... 2020 but not 2000
  116.         IF i <> 30 THEN d = d + 1 'fix for year 2000
  117.     NEXT
  118.     IF y <> 30 THEN '!!!!!!!!!!!!!!!!!! Unless the current year is 2000 !!!!!!!!!!!!!
  119.         IF m > 2 AND (y MOD 4 = 2) THEN d = d + 1 'fix leap year adjustment for year y
  120.     END IF
  121.     s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  122.     BmodTimeStamp## = (s~&& + t##)
  123.  
  124.  
  125. 'https://www.qb64.org/forum/index.php?topic=1638.msg108566#msg108566
  126. 'Steve last edit 10:58 AM 2019-08-20
  127. FUNCTION TimeStamp## (d$, t##) 'date and timer
  128.     'Based on Unix Epoch time, which starts at year 1970.
  129.     'Minor fixes to leap year logic by Bplus.  Many thanks!
  130.     l = INSTR(d$, "-")
  131.     l1 = INSTR(l + 1, d$, "-")
  132.     m = VAL(LEFT$(d$, l))
  133.     d = VAL(MID$(d$, l + 1))
  134.     y = VAL(MID$(d$, l1 + 1)) - 1970
  135.     FOR i = 1 TO m
  136.         SELECT CASE i 'Add the number of days for each previous month passed
  137.             CASE 1: d = d 'January doestn't have any carry over days.
  138.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  139.             CASE 3: d = d + 28
  140.             CASE 5, 7, 10, 12: d = d + 30
  141.         END SELECT
  142.     NEXT
  143.     FOR i = 1 TO y
  144.         d = d + 365
  145.     NEXT
  146.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year.
  147.         IF i <> 30 THEN d = d + 1 'add an extra day for leap year every 4 years, starting in 1970, but skip year 2000
  148.     NEXT
  149.  
  150.     'unless the current year is 2000!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
  151.     IF y <> 30 THEN
  152.         IF m > 2 AND (y MOD 4 = 2) THEN d = d + 1 'fix for leap year, for the current year.
  153.     END IF
  154.  
  155.     s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  156.     TimeStamp## = (s~&& + t##)
  157.  
  158.  
It stopped twice while I was testing. The first time because I didn't increment days for leap years correctly because I was using a different year formula, March 1, 1972, the 2nd time caught the bug for checking the y year if 2000, March 1, 2000. Hey Y2K bug strikes again!

The two TimeStamp## functions produce different results:

BmodTimeStamp## has 0 for date 01-01-1970 0 AM, because I subtract 1 from d calculated off Date$, that Day should not count as a full day. Also all the sub variables are DIM and the loop counting Days up is a one liner formula: d = d + 365 * y. I also removed CASE 1: d = d because it wasn't needed.

Steve's TimeStamp## function as of 11 AM this morning is exactly a days worth of seconds more for 01-01-1970 0 AM and I have fixed the same for the 2000 no leap year bug.

I think the BmodTimeStamp## is the more accrate.



Title: Re: Function Timestamp
Post by: petoro on August 21, 2019, 04:40:02 am
In fact 2000 WAS a leap year as usual. It is because it was divisible but 100 BUT ALSO by 400!
Title: Re: Function Timestamp
Post by: SMcNeill on August 21, 2019, 04:57:34 am
You're still glitching bplus...

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 640, 32)
  2. FOR i = 1970 TO 2005
  3.  
  4.     PRINT i, BmodTimeStamp##("03-01-" + STR$(i), 0), TimeStamp("03-01-" + STR$(i), 0);
  5.     IF i = 2000 THEN PRINT " <== GLITCH STARTING" ELSE PRINT
  6.  
  7.  
  8. ' b mod TimeStamp fixed. 2019-08-20 twiddled somemore and tested with code above
  9. FUNCTION BmodTimeStamp## (d$, t##) 'date and timer
  10.     DIM l AS INTEGER, l1 AS INTEGER, i AS INTEGER, s~&&
  11.     DIM m AS INTEGER, y AS INTEGER, d AS INTEGER
  12.     l = INSTR(d$, "-")
  13.     l1 = INSTR(l + 1, d$, "-")
  14.     m = VAL(LEFT$(d$, l))
  15.     d = VAL(MID$(d$, l + 1)) - 1 '<<<<<<<<<< the day of date is partial, so count of full days is 1 less!!
  16.     y = VAL(MID$(d$, l1 + 1)) - 1970
  17.     FOR i = 1 TO m 'count up days for year y
  18.         SELECT CASE i 'Add the number of days for each previous month passed, case 1 no change needed <<<<<<<<<<< removed case 1 line
  19.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  20.             CASE 3: d = d + 28
  21.             CASE 5, 7, 10, 12: d = d + 30
  22.         END SELECT
  23.     NEXT
  24.     d = d + 365 * y ' <<<<<<<<<<<<<<< Steve uses loop number of days before counting leap years
  25.     FOR i = 2 TO y - 1 STEP 4 ' to y-1 not y, leap years 1972, 1976, 1980... 2020 but not 2000
  26.         IF i <> 30 THEN d = d + 1 'fix for year 2000
  27.     NEXT
  28.     IF y <> 30 THEN '!!!!!!!!!!!!!!!!!! Unless the current year is 2000 !!!!!!!!!!!!!
  29.         IF m > 2 AND (y MOD 4 = 2) THEN d = d + 1 'fix leap year adjustment for year y
  30.     END IF
  31.     s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  32.     BmodTimeStamp## = (s~&& + t##)
  33.  
  34. FUNCTION TimeStamp## (d$, t##) 'date and timer
  35.     'Based on Unix Epoch time, which starts at year 1970.
  36.     IF y < 1970 THEN TimeStamp## = -1 'a failure message, as there was no Unix Epoch Time before Jan 01, 1970.
  37.     l = INSTR(d$, "-")
  38.     l1 = INSTR(l + 1, d$, "-")
  39.     m = VAL(LEFT$(d$, l))
  40.     d = VAL(MID$(d$, l + 1))
  41.     y = VAL(MID$(d$, l1 + 1)) - 1970
  42.     FOR i = 1 TO m 'for this year,
  43.         SELECT CASE i 'Add the number of days for each previous month passed
  44.             CASE 1: d = d 'January doestn't have any carry over days.
  45.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  46.             CASE 3 'Feb might be a leap year
  47.                 IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
  48.                     d = d + 29 'its a leap year
  49.                     IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
  50.                         d = d - 1 'the year is divisible by 100, and not divisible by 400
  51.                     END IF
  52.                 ELSE 'year not divisible by 4, no worries
  53.                     d = d + 28
  54.                 END IF
  55.             CASE 5, 7, 10, 12: d = d + 30
  56.         END SELECT
  57.     NEXT
  58.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  59.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
  60.         d = d + 1 'add an extra day every leap year
  61.         IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  62.     NEXT
  63.     s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  64.     TimeStamp## = (s~&& + t##)

With the original ExtendedTimer on the forums here, I was wondering WHY we got the correct answer, without subtracting a day from our date entry.  It's because we were completely handling the leap years wrongly to begin with... The year 2000 *IS* a leap year, so by taking a day off for it (when we shouldn't have), it shifted the answer back a day, giving us the correct time for TODAY...

Which ended up making it one of those glitches which actually fixed another glitch, which ended up giving the proper result when it shouldn't have! Testing it as a TimeStamp, which allows us to flow up and down to any particular date, allowed us to finally showcase the glitch and make adjustments to it.

Unfortunately, by correcting one glitch (subtracting one from the day), you've now left the second glitch to run without correction (the false 2000 leap year subtraction), meaning things are still just as broken as ever!

I'm thinking the above fixes all issues and gets us up to EUT compliance, but test it out for yourself and see what you think.  If it passes muster this time around, I'll redo ExtendedTimer to be correct as well, and we'll have STx correct the code in the toolbox.

The toolbox ExtendedTimer gives us the right result just because it's wrong at being wrong!  0_o!!
Title: Re: Function Timestamp
Post by: SMcNeill on August 21, 2019, 04:59:11 am
In fact 2000 WAS a leap year as usual. It is because it was divisible but 100 BUT ALSO by 400!

I was correcting that as you posted.  I think the latest version here takes all those subtle variations into account:

Code: QB64: [Select]
  1. FUNCTION TimeStamp## (d$, t##) 'date and timer
  2.     'Based on Unix Epoch time, which starts at year 1970.
  3.     IF y < 1970 THEN TimeStamp## = -1 'a failure message, as there was no Unix Epoch Time before Jan 01, 1970.
  4.     l = INSTR(d$, "-")
  5.     l1 = INSTR(l + 1, d$, "-")
  6.     m = VAL(LEFT$(d$, l))
  7.     d = VAL(MID$(d$, l + 1))
  8.     y = VAL(MID$(d$, l1 + 1)) - 1970
  9.     FOR i = 1 TO m 'for this year,
  10.         SELECT CASE i 'Add the number of days for each previous month passed
  11.             CASE 1: d = d 'January doestn't have any carry over days.
  12.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  13.             CASE 3 'Feb might be a leap year
  14.                 IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
  15.                     d = d + 29 'its a leap year
  16.                     IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
  17.                         d = d - 1 'the year is divisible by 100, and not divisible by 400
  18.                     END IF
  19.                 ELSE 'year not divisible by 4, no worries
  20.                     d = d + 28
  21.                 END IF
  22.             CASE 5, 7, 10, 12: d = d + 30
  23.         END SELECT
  24.     NEXT
  25.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  26.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
  27.         d = d + 1 'add an extra day every leap year
  28.         IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  29.     NEXT
  30.     s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  31.     TimeStamp## = (s~&& + t##)
Title: Re: Function Timestamp
Post by: SMcNeill on August 21, 2019, 05:41:46 am
And if you notice, I just toss an error value for when we end up below 1970 and look for a timestamp.  At that point, we have to count time in reverse to generate negative numbers, and I just didn't feel like putting in the effort for it.  :P

DEC 31, 1969, 23:59:59 = -1
DEC 31, 1969, 23:59:58 = -2
... and so on.

With the medications I'm on, I'm surprised I managed to count forward to get to the point where it's currently working properly; I sure don't feel like making it count backwards at the moment.  I leave that mod to Bplus, if he feels like adding it, otherwise positive timestamps are good enough for my needs...  ;)
Title: Re: Function Timestamp
Post by: STxAxTIC on August 21, 2019, 06:20:08 am
Thanks for your diligence boys. I'll let this topic settle down for a short bit before updating our curated code. I unfortunately don't have the most time in the world to follow all the posts so preemptive apologies if I ask for something in a few days that should have been obvious to me.
Title: Re: Function Timestamp
Post by: bplus on August 21, 2019, 09:09:13 am
In fact 2000 WAS a leap year as usual. It is because it was divisible but 100 BUT ALSO by 400!

Yikes! nothing like wasting allot of time under a false premise.

Well it's not wasted if I learn something positive from it!



Title: Re: Function Timestamp
Post by: bplus on August 21, 2019, 09:25:14 am
Quote
The toolbox ExtendedTimer gives us the right result just because it's wrong at being wrong!  0_o!!

The toolbox code last edited August 11, 2019 is still flawed when the current month is < 3
Code: QB64: [Select]
  1. SHELL "https://www.epochconverter.com/"
  2.     CLS
  3.     PRINT TIMER, INT(ExtendedTimer)
  4.     PRINT "Compare to the time at https://www.epochconverter.com/"
  5.     _DISPLAY
  6.     _LIMIT 10
  7.  
  8. FUNCTION ExtendedTimer##
  9.     d$ = DATE$
  10.     l = INSTR(d$, "-")
  11.     l1 = INSTR(l + 1, d$, "-")
  12.     m = VAL(LEFT$(d$, l))
  13.     d = VAL(MID$(d$, l + 1))
  14.     y = VAL(MID$(d$, l1 + 1)) - 1970
  15.     FOR i = 1 TO m
  16.         SELECT CASE i 'Add the number of days for each previous month passed
  17.             CASE 1: d = d 'January doestn't have any carry over days.
  18.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  19.             CASE 3: d = d + 28
  20.             CASE 5, 7, 10, 12: d = d + 30
  21.         END SELECT
  22.     NEXT
  23.     FOR i = 1 TO y
  24.         d = d + 365
  25.     NEXT
  26.     FOR i = 2 TO y STEP 4
  27.         IF m > 2 THEN d = d + 1 'add an extra day for leap year every 4 years, starting in 1970
  28.     NEXT
  29.     d = d - 1 'for year 2000
  30.     s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  31.     ExtendedTimer## = (s~&& + TIMER)

Title: Re: Function Timestamp
Post by: petoro on August 21, 2019, 01:15:01 pm
Yikes! nothing like wasting allot of time under a false premise.

Well it's not wasted if I learn something positive from it!

The western calendar has some twisted details :)
Title: Re: Function Timestamp
Post by: bplus on August 21, 2019, 01:42:12 pm
The western calendar has some twisted details :)

:)) What's twisted are the Earth's rotations and revolutions.
Title: Re: Function Timestamp
Post by: SMcNeill on August 22, 2019, 11:18:55 am
TimeStamp should now work with all dates for us, even giving us the negative timestamps for dates/times before 1970.

Code: QB64: [Select]
  1. SHELL "https://www.epochconverter.com/"
  2. PRINT "Compare to time stamps generated at the website which popped up in your browser.https://www.epochconverter.com/"
  3.  
  4.     PRINT
  5.     PRINT
  6.     INPUT "Give me a DATE$ in format of DD-MM-YYYY"; d$
  7.     IF d$ = "" THEN SYSTEM
  8.     INPUT "Give me a TIMER value from 0 to 86399.999"; t##
  9.     PRINT
  10.     PRINT
  11.     PRINT "Your current timestamp is =>:"; TimeStamp(d$, t##)
  12.  
  13.  
  14. FUNCTION TimeStamp## (d$, t##) 'date and timer
  15.     'Based on Unix Epoch time, which starts at year 1970.
  16.     DIM s AS _FLOAT
  17.  
  18.     l = INSTR(d$, "-")
  19.     l1 = INSTR(l + 1, d$, "-")
  20.     m = VAL(LEFT$(d$, l))
  21.     d = VAL(MID$(d$, l + 1))
  22.     y = VAL(MID$(d$, l1 + 1))
  23.     IF y < 1970 THEN 'calculate shit backwards
  24.         SELECT CASE m 'turn the day backwards for the month
  25.             CASE 1, 3, 5, 7, 8, 10, 12: d = 31 - d '31 days
  26.             CASE 2: d = 28 - d 'special 28 or 29.
  27.             CASE 4, 6, 9, 11: d = 30 - d '30 days
  28.         END SELECT
  29.         IF y MOD 4 = 0 AND m < 3 THEN 'check for normal leap year, and we're before it...
  30.             d = d + 1 'assume we had a leap year, subtract another day
  31.             IF y MOD 100 = 0 AND y MOD 400 <> 0 THEN d = d - 1 'not a leap year if year is divisible by 100 and not 400
  32.         END IF
  33.  
  34.         'then count the months that passed after the current month
  35.         FOR i = m + 1 TO 12
  36.             SELECT CASE i
  37.                 CASE 2: d = d + 28
  38.                 CASE 3, 5, 7, 8, 10, 12: d = d + 31
  39.                 CASE 4, 6, 9, 11: d = d + 30
  40.             END SELECT
  41.         NEXT
  42.  
  43.         'we should now have the entered year calculated.  Now lets add in for each year from this point to 1970
  44.         d = d + 365 * (1969 - y) '365 days per each standard year
  45.         FOR i = 1968 TO y + 1 STEP -4 'from 1968 onwards,backwards, skipping the current year (which we handled previously in the FOR loopp)
  46.             d = d + 1 'subtract an extra day every leap year
  47.             IF (i MOD 100) = 0 AND (i MOD 400) <> 0 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  48.         NEXT
  49.         s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  50.         TimeStamp## = -(s## + 24 * 60 * 60 - t##)
  51.         EXIT FUNCTION
  52.     ELSE
  53.         y = y - 1970
  54.     END IF
  55.  
  56.     FOR i = 1 TO m 'for this year,
  57.         SELECT CASE i 'Add the number of days for each previous month passed
  58.             CASE 1: d = d 'January doestn't have any carry over days.
  59.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  60.             CASE 3 'Feb might be a leap year
  61.                 IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
  62.                     d = d + 29 'its a leap year
  63.                     IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
  64.                         d = d - 1 'the year is divisible by 100, and not divisible by 400
  65.                     END IF
  66.                 ELSE 'year not divisible by 4, no worries
  67.                     d = d + 28
  68.                 END IF
  69.             CASE 5, 7, 10, 12: d = d + 30
  70.         END SELECT
  71.     NEXT
  72.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  73.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
  74.         d = d + 1 'add an extra day every leap year
  75.         IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  76.     NEXT
  77.     s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  78.     TimeStamp## = (s## + t##)
  79.  
  80. FUNCTION ExtendedTimer##
  81.     ExtendedTimer = TimeStamp(DATE$, TIMER)
Title: Re: Function Timestamp
Post by: bplus on August 22, 2019, 03:24:08 pm
LOL
Quote
   IF y < 1970 THEN 'calculate shit backwards
Nice to extend this back!

Steve, have you considered a timestamp decoder ring? a reverse function to restore date and time.

Also something I've noticed from start:
Code: QB64: [Select]
  1.     l = INSTR(d$, "-")
  2.     l1 = INSTR(l + 1, d$, "-")
  3.     m = VAL(LEFT$(d$, l))
  4.     d = VAL(MID$(d$, l + 1))
  5.     y = VAL(MID$(d$, l1 + 1))
  6.  

loose l and l1 variables and use straight MID$ extraction of m, d, y and you loose the restriction of the separator having to be "-" thusly a "/", a space, any single character would work just as well.
Title: Re: Function Timestamp
Post by: bplus on August 22, 2019, 03:47:43 pm
Wait... before we spend another second (or I in checking code of this coding exercise), can someone review for me the practical benefits it might serve?

Steve, you said yourself you use a different system for autosave, one I can appreciate for it's transparency.

Wait... maybe I can for myself, using it to calculate date and time differences. My code that I worked out yesterday was pretty inefficient counting one by one the days until I reach the later date. Converting to seconds, subtracting seconds and then converting to days hours minutes secs.... might be easier or more efficient.
Title: Re: Function Timestamp
Post by: SMcNeill on August 22, 2019, 04:05:20 pm
Wait... before we spend another second (or I in checking code of this coding exercise), can someone review for me the practical benefits it might serve?

Steve, you said yourself you use a different system for autosave, one I can appreciate for it's transparency.

Wait... maybe I can for myself, using it to calculate date and time differences. My code that I worked out yesterday was pretty inefficient counting one by one the days until I reach the later date. Converting to seconds, subtracting seconds and then converting to days hours minutes secs.... might be easier or more efficient.

I haven’t used it for a time stamp before (which is why there was so many little glitches to work out); what I use all the time is the ExtendedTimer.  QB64 has 2 ways we can track time — TIME$ and TIMER. For most usages, I find myself using TIMER a lot more than I would TIME$ (it’s hard to add and subtract hours, minutes, and seconds...), but TIMER has one great flaw...

MIDNIGHT!!

Start a program at 11:59:59 PM (86399 seconds), and wait 10 seconds to do something....  and you’ll wait forever with IF TIMER > StartTime + 10 THEN....

Your timer goes back to 0 at midnight, so you’ll never pass (86409 seconds) — putting your program into an endless loop.

Thus, I added ExtendedTimer.  It tracks time with days, months, years, so midnight is no longer an issue.  Where “IF TIMER > StartTime + 10 THEN....” fails at midnight, “IF ExtendedTimer > StartTime + 10 THEN...” doesn’t.
Title: Re: Function Timestamp
Post by: bplus on August 22, 2019, 04:43:47 pm
Easier way, check if Timer < StartTime and fix accordingly with a day's worth of secs, that saves bloating code with another procedure  If Timer < StartTime then StartTime = StartTime - 24*60*60

Extended timer would work if run something more than a day (I don't) and Timer is no good for that kind usage either.
Title: Re: Function Timestamp
Post by: STxAxTIC on August 24, 2019, 05:48:42 pm
Heya boys,

I apologize for not following this thread to a tee, and not doing my proper reading on the tit-for-tat that happened... but can one of you fine gentleman reply to this with what *should* appear in the toolbox? Thanks kindly.
Title: Re: Function Timestamp
Post by: bplus on August 24, 2019, 06:00:09 pm
Heya boys,

I apologize for not following this thread to a tee, and not doing my proper reading on the tit-for-tat that happened... but can one of you fine gentleman reply to this with what *should* appear in the toolbox? Thanks kindly.

Steve has something very interesting posted in #19 August 22

I have not had a chance to give it a test drive, I did want to check and see how it did calculating time & date differences for my submission for code challenge "Count Down 2020" but then Ken came up with more interesting problem and I got side tracked.

Not that you need my seal of approval, but it would be nice if someone tried to break it before submitting to librarian to save librarian's valuable time spent editing buggy code.
Title: Re: Function Timestamp
Post by: SMcNeill on August 24, 2019, 06:18:30 pm
Here's what I'd call the "official version" of these two routines reworked for goodness's sake:

Code: QB64: [Select]
  1. SHELL "https://www.epochconverter.com/"
  2. PRINT "Compare to time stamps generated at the website which popped up in your browser.https://www.epochconverter.com/"
  3.  
  4. CONST MyTimeZone## = 4 * 3600
  5.  
  6.     _LIMIT 1
  7.     CLS
  8.     PRINT TimeStamp(DATE$, TIMER + MyTimeZone) 'Timezone difference with GMT, which is what the webpage sometimes points to.
  9.     '                                           If the times seem off from the website, you'll want to change the timezone
  10.     '                                           offset to match your current time zone.
  11.     PRINT ExtendedTimer 'Unix Epoch Timer based on local time.
  12.     _DISPLAY
  13.  
  14.  
  15. FUNCTION TimeStamp## (d$, t##) 'date and timer
  16.     'Based on Unix Epoch time, which starts at year 1970.
  17.     DIM s AS _FLOAT
  18.  
  19.     l = INSTR(d$, "-")
  20.     l1 = INSTR(l + 1, d$, "-")
  21.     m = VAL(LEFT$(d$, l))
  22.     d = VAL(MID$(d$, l + 1))
  23.     y = VAL(MID$(d$, l1 + 1))
  24.     IF y < 1970 THEN 'calculate shit backwards
  25.         SELECT CASE m 'turn the day backwards for the month
  26.             CASE 1, 3, 5, 7, 8, 10, 12: d = 31 - d '31 days
  27.             CASE 2: d = 28 - d 'special 28 or 29.
  28.             CASE 4, 6, 9, 11: d = 30 - d '30 days
  29.         END SELECT
  30.         IF y MOD 4 = 0 AND m < 3 THEN 'check for normal leap year, and we're before it...
  31.             d = d + 1 'assume we had a leap year, subtract another day
  32.             IF y MOD 100 = 0 AND y MOD 400 <> 0 THEN d = d - 1 'not a leap year if year is divisible by 100 and not 400
  33.         END IF
  34.  
  35.         'then count the months that passed after the current month
  36.         FOR i = m + 1 TO 12
  37.             SELECT CASE i
  38.                 CASE 2: d = d + 28
  39.                 CASE 3, 5, 7, 8, 10, 12: d = d + 31
  40.                 CASE 4, 6, 9, 11: d = d + 30
  41.             END SELECT
  42.         NEXT
  43.  
  44.         'we should now have the entered year calculated.  Now lets add in for each year from this point to 1970
  45.         d = d + 365 * (1969 - y) '365 days per each standard year
  46.         FOR i = 1968 TO y + 1 STEP -4 'from 1968 onwards,backwards, skipping the current year (which we handled previously in the FOR loop)
  47.             d = d + 1 'subtract an extra day every leap year
  48.             IF (i MOD 100) = 0 AND (i MOD 400) <> 0 THEN d = d - 1 'but skipping every year divisible by 100, but not 400
  49.         NEXT
  50.         s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  51.         TimeStamp## = -(s## + 24 * 60 * 60 - t##)
  52.         EXIT FUNCTION
  53.     ELSE
  54.         y = y - 1970
  55.     END IF
  56.  
  57.     FOR i = 1 TO m 'for this year,
  58.         SELECT CASE i 'Add the number of days for each previous month passed
  59.             CASE 1: d = d 'January doestn't have any carry over days.
  60.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  61.             CASE 3 'Feb might be a leap year
  62.                 IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
  63.                     d = d + 29 'its a leap year
  64.                     IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
  65.                         d = d - 1 'the year is divisible by 100, and not divisible by 400
  66.                     END IF
  67.                 ELSE 'year not divisible by 4, no worries
  68.                     d = d + 28
  69.                 END IF
  70.             CASE 5, 7, 10, 12: d = d + 30
  71.         END SELECT
  72.     NEXT
  73.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  74.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
  75.         d = d + 1 'add an extra day every leap year
  76.         IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  77.     NEXT
  78.     s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  79.     TimeStamp## = (s## + t##)
  80.  
  81. FUNCTION ExtendedTimer##
  82.     'Simplified version of the TimeStamp routine, streamlined to only give positive values based on the current timer.
  83.     'Note:  Only good until the year 2100, as we don't do all the fancy calculations for leap years.
  84.     'A timer should work quickly and efficiently in the background; and the less we do, the less lag we might insert
  85.     'into a program.
  86.  
  87.     DIM m AS INTEGER, d AS INTEGER, y AS INTEGER
  88.     DIM s AS _FLOAT, day AS STRING
  89.     day = DATE$
  90.     m = VAL(LEFT$(day, 2))
  91.     d = VAL(MID$(day, 4, 2))
  92.     y = VAL(RIGHT$(day, 4)) - 1970
  93.     SELECT CASE m 'Add the number of days for each previous month passed
  94.         CASE 2: d = d + 31
  95.         CASE 3: d = d + 59
  96.         CASE 4: d = d + 90
  97.         CASE 5: d = d + 120
  98.         CASE 6: d = d + 151
  99.         CASE 7: d = d + 181
  100.         CASE 8: d = d + 212
  101.         CASE 9: d = d + 243
  102.         CASE 10: d = d + 273
  103.         CASE 11: d = d + 304
  104.         CASE 12: d = d + 334
  105.     END SELECT
  106.     IF (y MOD 4) = 2 AND m > 2 THEN d = d + 1 'add a day if this is leap year and we're past february
  107.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  108.     d = d + (y + 2) \ 4 'add in days for leap years passed
  109.     s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  110.     ExtendedTimer## = (s + TIMER)
  111.  

The demo should speak for itself, I'd hope.  ;)
Title: Re: Function Timestamp
Post by: bplus on August 24, 2019, 09:12:38 pm
Hi Steve,

I am using this code to calculate difference in dates using your timeStamp## and code I used in my last post in Count  Down 2020:
Code: QB64: [Select]
  1.  
  2. FUNCTION TimeStampDiff$ (LaterDate$, LaterTime##, EarlierDate$, EarlierTime##)
  3.     secLate## = TimeStamp##(LaterDate$, LaterTime##)
  4.     secEarly## = TimeStamp##(EarlierDate$, EarlierTime##)
  5.     secDiff = secLate## - secEarly##
  6.     'covert to days, hours, minutes, secs I am dropping fraction secs for test
  7.     days = INT(secDiff / 86400)
  8.     secDiff = secDiff - days * 86400
  9.     hours = INT(secDiff / 3600)
  10.     secDiff = secDiff - hours * 3600
  11.     minutes = INT(secDiff / 60)
  12.     secs = INT(secDiff - minutes * 60)
  13.     TimeStampDiff$ = _TRIM$(STR$(days)) + " Days and " + _TRIM$(STR$(hours)) + " Hours, " + _TRIM$(STR$(minutes)) + " Minutes, " + _TRIM$(STR$(secs))
  14.  

The good news we agree for years >=1970, bad news there is difference in days for years earlier than 1970.
This is the completely new section of your timeStamp## code that I thought should be tested because the web site can't verify your numbers in those circumstances.

I am currently revising the test to maybe help see what is off.
Title: Re: Function Timestamp
Post by: SMcNeill on August 24, 2019, 09:34:12 pm
You can compare with the page here: https://www.epochconverter.com/

Times were matching at my last tests, unless I posted a glitchy version on the forums here...  I’ll recheck results again to see what’s up.
Title: Re: Function Timestamp
Post by: bplus on August 24, 2019, 09:51:22 pm
Hi Steve,

It's the new part of your code where you attempt dates before 1970, here is my test code:
Code: QB64: [Select]
  1. _TITLE "Test Steve timeStamp" 'B+ test 2019-08-24
  2. '2019-08-24 Quick test Steve timestamp by comparing DiffDateTime$ to TimeStampDiff$
  3. 'I am just testing day counts
  4.  
  5. SCREEN _NEWIMAGE(600, 760, 32)
  6. times$ = "00:00:00": times## = 0
  7.  
  8. dates$(3) = "08-24-2019": dates$(2) = "01-01-2020": dates$(1) = "01-01-2021": dates$(0) = "01-01-2025"
  9. dates$(4) = "01-01-2019": dates$(5) = "01-01-1970": dates$(6) = "01-01-1815"
  10.  
  11. FOR i = 0 TO 5
  12.     FOR j = i + 1 TO 6
  13.         PRINT dates$(i); " Minus "; dates$(j)
  14.         PRINT DiffDateTime$(DateTime$(dates$(i), times$), DateTime$(dates$(j), times$))
  15.         PRINT TimeStampDiff$(dates$(i), time##, dates$(j), time##)
  16.         PRINT
  17.     NEXT
  18.     INPUT "OK ... press enter "; w$
  19.     CLS
  20. d1970$ = "01-01-1970"
  21. FOR y = 1970 TO 1950 STEP -1
  22.     d$ = "01-01-" + _TRIM$(STR$(y))
  23.     PRINT d1970$; " Minus "; d$
  24.     PRINT DiffDateTime$(DateTime$(d1970$, times$), DateTime$(d$, times$))
  25.     PRINT TimeStampDiff$(d1970$, time##, d$, time##)
  26.     PRINT
  27.     IF y MOD 5 = 0 THEN
  28.         INPUT "OK ... press enter "; w$
  29.         CLS
  30.     END IF
  31.  
  32. ' I used this code for Count Down 2020
  33. 'note: this uses 2 dates and times formatted with DateTime$() Function
  34. FUNCTION DiffDateTime$ (LaterDate$, MinusEarlierDate$)
  35.     es = VAL(MID$(MinusEarlierDate$, 18, 2))
  36.     ls = VAL(MID$(LaterDate$, 18, 2))
  37.  
  38.     em = VAL(MID$(MinusEarlierDate$, 15, 2))
  39.     lm = VAL(MID$(LaterDate$, 15, 2))
  40.  
  41.     eh = VAL(MID$(MinusEarlierDate$, 12, 2))
  42.     lh = VAL(MID$(LaterDate$, 12, 2))
  43.  
  44.     ed = VAL(MID$(MinusEarlierDate$, 9, 2))
  45.     ld = VAL(MID$(LaterDate$, 9, 2))
  46.  
  47.     emm = VAL(MID$(MinusEarlierDate$, 6, 2))
  48.     lmm = VAL(MID$(LaterDate$, 6, 2))
  49.  
  50.     ey = VAL(MID$(MinusEarlierDate$, 1, 4))
  51.     ly = VAL(MID$(LaterDate$, 1, 4))
  52.  
  53.     IF es > ls THEN ls = ls + 60: lm = lm - 1
  54.     DiffDateTime$ = STR$(ls - es) + " secs"
  55.  
  56.     IF em > lm THEN lm = lm + 60: lh = lh - 1
  57.     DiffDateTime$ = STR$(lm - em) + " mins" + DiffDateTime$
  58.  
  59.     IF eh > lh THEN lh = lh + 24: ld = ld - 1
  60.     DiffDateTime$ = STR$(lh - eh) + " hours" + DiffDateTime$
  61.  
  62.     ''did we barrow off day
  63.     IF ld = 0 THEN
  64.         SELECT CASE lmm
  65.             CASE 1: ly = ly - 1: lmm = 12: ld = 31
  66.             CASE 3: IF IsLeapYear(ly) = 1 THEN lmm = 2: ld = 29 ELSE lmm = 2: ld = 28
  67.             CASE 5, 7, 8, 10, 12: lmm = lmm - 1: ld = 30
  68.             CASE 2, 4, 6, 9, 11: lmm = lmm - 1: ld = 31
  69.         END SELECT
  70.     END IF
  71.     'PRINT ly, lmm, ld   ' check target and start
  72.     'PRINT ey, emm, ed
  73.  
  74.     'now count days
  75.     DO
  76.         IF ly = ey THEN
  77.             IF lmm = emm THEN
  78.                 IF ld = ed THEN EXIT DO '  all date numbers match, done calc
  79.             END IF
  80.         END IF
  81.         ed = ed + 1
  82.         cnt = cnt + 1
  83.         IF ed = 29 AND emm = 2 THEN
  84.             'is it leap year
  85.             IF IsLeapYear%(ey) = 1 THEN
  86.                 'pass
  87.             ELSE
  88.                 emm = 3: ed = 1
  89.             END IF
  90.         ELSEIF ed = 30 AND emm = 2 THEN 'must be leap year
  91.             emm = 3: ed = 1
  92.         ELSEIF ed = 31 THEN
  93.             IF emm = 4 OR emm = 6 OR emm = 9 OR emm = 11 THEN
  94.                 emm = emm + 1: ed = 1
  95.             END IF
  96.         ELSEIF ed = 32 THEN
  97.             IF emm = 12 THEN
  98.                 ed = 1: emm = 1: ey = ey + 1
  99.             ELSE
  100.                 ed = 1: emm = emm + 1
  101.             END IF
  102.         END IF
  103.         'PRINT ey, emm, ed, ly; " "; lmm; " "; ld   'Check progress
  104.         '_LIMIT 2
  105.     LOOP
  106.     DiffDateTime$ = _TRIM$(STR$(cnt)) + " Days and" + DiffDateTime$
  107.  
  108. FUNCTION CurrentDateTime$
  109.     CurrentDateTime$ = "    -  -  _  :  :  "
  110.     MID$(CurrentDateTime$, 1, 4) = MID$(DATE$, 7, 4)
  111.     MID$(CurrentDateTime$, 6, 5) = MID$(DATE$, 1, 5)
  112.     MID$(CurrentDateTime$, 12, 8) = TIME$
  113.  
  114. FUNCTION DateTime$ (mm_dd_yy$, hh_mm_ss$)
  115.     DateTime$ = "    -  -  _  :  :  "
  116.     MID$(DateTime$, 1, 4) = MID$(mm_dd_yy$, 7, 4)
  117.     MID$(DateTime$, 6, 5) = MID$(mm_dd_yy$, 1, 5)
  118.     MID$(DateTime$, 12, 8) = hh_mm_ss$
  119.  
  120. FUNCTION IsLeapYear% (yr) 'mod from Pete's calendar this is a very clear calc
  121.     IF yr MOD 4 = 0 THEN
  122.         IF yr MOD 100 = 0 THEN
  123.             IF yr MOD 400 = 0 THEN IsLeapYear = 1
  124.         ELSE
  125.             IsLeapYear = 1
  126.         END IF
  127.     END IF
  128.  
  129. 'this calc date time diff using Steve' TimeStamp## secs
  130. FUNCTION TimeStampDiff$ (LaterDate$, LaterTime##, EarlierDate$, EarlierTime##)
  131.     secLate## = TimeStamp##(LaterDate$, LaterTime##)
  132.     secEarly## = TimeStamp##(EarlierDate$, EarlierTime##)
  133.     secDiff = secLate## - secEarly##
  134.     'covert to days, hours, minutes, secs I am dropping fraction secs for test
  135.     days = INT(secDiff / 86400)
  136.     secDiff = secDiff - days * 86400
  137.     hours = INT(secDiff / 3600)
  138.     secDiff = secDiff - hours * 3600
  139.     minutes = INT(secDiff / 60)
  140.     secs = INT(secDiff - minutes * 60)
  141.     TimeStampDiff$ = _TRIM$(STR$(days)) + " Days and " + _TRIM$(STR$(hours)) + " Hours, " + _TRIM$(STR$(minutes)) + " Minutes, " + _TRIM$(STR$(secs))
  142.  
  143. ' Steve's latest version
  144. ' https://www.qb64.org/forum/index.php?topic=1638.msg108650#msg108650
  145. FUNCTION TimeStamp## (d$, t##) 'date and timer
  146.     'Based on Unix Epoch time, which starts at year 1970.
  147.  
  148.     m = VAL(LEFT$(d$, 2))
  149.     d = VAL(MID$(d$, 4, 2))
  150.     y = VAL(RIGHT$(d$, 4))
  151.     IF y < 1970 THEN 'calculate shit backwards
  152.         SELECT CASE m 'turn the day backwards for the month
  153.             CASE 1, 3, 5, 7, 8, 10, 12: d = 31 - d '31 days
  154.             CASE 2: d = 28 - d 'special 28 or 29.
  155.             CASE 4, 6, 9, 11: d = 30 - d '30 days
  156.         END SELECT
  157.         IF y MOD 4 = 0 AND m < 3 THEN 'check for normal leap year, and we're before it...
  158.             d = d - 1 'assume we had a leap year, subtract another day
  159.             IF y MOD 100 = 0 AND y MOD 400 <> 0 THEN d = d + 1 'not a leap year if year is divisible by 100 and not 400
  160.         END IF
  161.  
  162.         'then count the months that passed after the current month
  163.         FOR i = m + 1 TO 12
  164.             SELECT CASE i
  165.                 CASE 2: d = d - 28
  166.                 CASE 3, 5, 7, 8, 10, 12: d = d - 31
  167.                 CASE 4, 6, 9, 11: d = d - 30
  168.             END SELECT
  169.         NEXT
  170.  
  171.         'we should now have the entered year calculated.  Now lets add in for each year from this point to 1970
  172.         d = d + 365 * (1969 - y) '365 days per each standard year
  173.         FOR i = 1968 TO y + 1 STEP -4 'from 1968 onwards,backwards, skipping the current year (which we handled previously in the FOR loopp)
  174.             d = d + 1 'subtract an extra day every leap year
  175.             IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  176.         NEXT
  177.         s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  178.         TimeStamp## = -(s## + 24 * 60 * 60 - t##)
  179.         EXIT FUNCTION
  180.     ELSE
  181.         y = y - 1970
  182.     END IF
  183.  
  184.     FOR i = 1 TO m 'for this year,
  185.         SELECT CASE i 'Add the number of days for each previous month passed
  186.             CASE 1: d = d 'January doestn't have any carry over days.
  187.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  188.             CASE 3 'Feb might be a leap year
  189.                 IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
  190.                     d = d + 29 'its a leap year
  191.                     IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
  192.                         d = d - 1 'the year is divisible by 100, and not divisible by 400
  193.                     END IF
  194.                 ELSE 'year not divisible by 4, no worries
  195.                     d = d + 28
  196.                 END IF
  197.             CASE 5, 7, 10, 12: d = d + 30
  198.         END SELECT
  199.     NEXT
  200.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  201.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
  202.         d = d + 1 'add an extra day every leap year
  203.         IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  204.     NEXT
  205.     s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  206.     TimeStamp## = (s## + t##)
  207.  
Title: Re: Function Timestamp
Post by: SMcNeill on August 24, 2019, 10:48:20 pm
Okies...  I have no idea what's going on, but somebody out there is screwing with me.  (Or else my medication is really screwing with me.  The function works, as posted, except the signs are backwards?!!)  How the BLEEP did I manage to screw up that perfectly???!!

Code: QB64: [Select]
  1. _TITLE "Test Steve timeStamp" 'B+ test 2019-08-24
  2. '2019-08-24 Quick test Steve timestamp by comparing DiffDateTime$ to TimeStampDiff$
  3. 'I am just testing day counts
  4.  
  5. SCREEN _NEWIMAGE(600, 760, 32)
  6. times$ = "00:00:00": times## = 0
  7.  
  8. dates$(3) = "08-24-2019": dates$(2) = "01-01-2020": dates$(1) = "01-01-2021": dates$(0) = "01-01-2025"
  9. dates$(4) = "01-01-2019": dates$(5) = "01-01-1970": dates$(6) = "01-01-1815"
  10.  
  11. FOR i = 0 TO 5
  12.     FOR j = i + 1 TO 6
  13.         PRINT dates$(i); " Minus "; dates$(j)
  14.         PRINT DiffDateTime$(DateTime$(dates$(i), times$), DateTime$(dates$(j), times$))
  15.         PRINT TimeStampDiff$(dates$(i), time##, dates$(j), time##)
  16.         PRINT
  17.     NEXT
  18.  
  19.     PRINT
  20.     PRINT
  21.     PRINT "UET for 01-01-1915:"; TimeStamp("01-01-1915", 0)
  22.     PRINT
  23.     PRINT
  24.     INPUT "OK ... press enter "; w$
  25.     CLS
  26.  
  27.  
  28.  
  29.  
  30. d1970$ = "01-01-1970"
  31. FOR y = 1970 TO 1950 STEP -1
  32.     d$ = "01-01-" + _TRIM$(STR$(y))
  33.     PRINT d1970$; " Minus "; d$
  34.     PRINT DiffDateTime$(DateTime$(d1970$, times$), DateTime$(d$, times$))
  35.     PRINT TimeStampDiff$(d1970$, time##, d$, time##)
  36.     PRINT
  37.     IF y MOD 5 = 0 THEN
  38.         INPUT "OK ... press enter "; w$
  39.         CLS
  40.     END IF
  41.  
  42. PRINT TimeStamp("01-01-1915", 0)
  43.  
  44.  
  45.  
  46.  
  47. ' I used this code for Count Down 2020
  48. 'note: this uses 2 dates and times formatted with DateTime$() Function
  49. FUNCTION DiffDateTime$ (LaterDate$, MinusEarlierDate$)
  50.     es = VAL(MID$(MinusEarlierDate$, 18, 2))
  51.     ls = VAL(MID$(LaterDate$, 18, 2))
  52.  
  53.     em = VAL(MID$(MinusEarlierDate$, 15, 2))
  54.     lm = VAL(MID$(LaterDate$, 15, 2))
  55.  
  56.     eh = VAL(MID$(MinusEarlierDate$, 12, 2))
  57.     lh = VAL(MID$(LaterDate$, 12, 2))
  58.  
  59.     ed = VAL(MID$(MinusEarlierDate$, 9, 2))
  60.     ld = VAL(MID$(LaterDate$, 9, 2))
  61.  
  62.     emm = VAL(MID$(MinusEarlierDate$, 6, 2))
  63.     lmm = VAL(MID$(LaterDate$, 6, 2))
  64.  
  65.     ey = VAL(MID$(MinusEarlierDate$, 1, 4))
  66.     ly = VAL(MID$(LaterDate$, 1, 4))
  67.  
  68.     IF es > ls THEN ls = ls + 60: lm = lm - 1
  69.     DiffDateTime$ = STR$(ls - es) + " secs"
  70.  
  71.     IF em > lm THEN lm = lm + 60: lh = lh - 1
  72.     DiffDateTime$ = STR$(lm - em) + " mins" + DiffDateTime$
  73.  
  74.     IF eh > lh THEN lh = lh + 24: ld = ld - 1
  75.     DiffDateTime$ = STR$(lh - eh) + " hours" + DiffDateTime$
  76.  
  77.     ''did we barrow off day
  78.     IF ld = 0 THEN
  79.         SELECT CASE lmm
  80.             CASE 1: ly = ly - 1: lmm = 12: ld = 31
  81.             CASE 3: IF IsLeapYear(ly) = 1 THEN lmm = 2: ld = 29 ELSE lmm = 2: ld = 28
  82.             CASE 5, 7, 8, 10, 12: lmm = lmm - 1: ld = 30
  83.             CASE 2, 4, 6, 9, 11: lmm = lmm - 1: ld = 31
  84.         END SELECT
  85.     END IF
  86.     'PRINT ly, lmm, ld   ' check target and start
  87.     'PRINT ey, emm, ed
  88.  
  89.     'now count days
  90.     DO
  91.         IF ly = ey THEN
  92.             IF lmm = emm THEN
  93.                 IF ld = ed THEN EXIT DO '  all date numbers match, done calc
  94.             END IF
  95.         END IF
  96.         ed = ed + 1
  97.         cnt = cnt + 1
  98.         IF ed = 29 AND emm = 2 THEN
  99.             'is it leap year
  100.             IF IsLeapYear%(ey) = 1 THEN
  101.                 'pass
  102.             ELSE
  103.                 emm = 3: ed = 1
  104.             END IF
  105.         ELSEIF ed = 30 AND emm = 2 THEN 'must be leap year
  106.             emm = 3: ed = 1
  107.         ELSEIF ed = 31 THEN
  108.             IF emm = 4 OR emm = 6 OR emm = 9 OR emm = 11 THEN
  109.                 emm = emm + 1: ed = 1
  110.             END IF
  111.         ELSEIF ed = 32 THEN
  112.             IF emm = 12 THEN
  113.                 ed = 1: emm = 1: ey = ey + 1
  114.             ELSE
  115.                 ed = 1: emm = emm + 1
  116.             END IF
  117.         END IF
  118.         'PRINT ey, emm, ed, ly; " "; lmm; " "; ld   'Check progress
  119.         '_LIMIT 2
  120.     LOOP
  121.     DiffDateTime$ = _TRIM$(STR$(cnt)) + " Days and" + DiffDateTime$
  122.  
  123. FUNCTION CurrentDateTime$
  124.     CurrentDateTime$ = "    -  -  _  :  :  "
  125.     MID$(CurrentDateTime$, 1, 4) = MID$(DATE$, 7, 4)
  126.     MID$(CurrentDateTime$, 6, 5) = MID$(DATE$, 1, 5)
  127.     MID$(CurrentDateTime$, 12, 8) = TIME$
  128.  
  129. FUNCTION DateTime$ (mm_dd_yy$, hh_mm_ss$)
  130.     DateTime$ = "    -  -  _  :  :  "
  131.     MID$(DateTime$, 1, 4) = MID$(mm_dd_yy$, 7, 4)
  132.     MID$(DateTime$, 6, 5) = MID$(mm_dd_yy$, 1, 5)
  133.     MID$(DateTime$, 12, 8) = hh_mm_ss$
  134.  
  135. FUNCTION IsLeapYear% (yr) 'mod from Pete's calendar this is a very clear calc
  136.     IF yr MOD 4 = 0 THEN
  137.         IF yr MOD 100 = 0 THEN
  138.             IF yr MOD 400 = 0 THEN IsLeapYear = 1
  139.         ELSE
  140.             IsLeapYear = 1
  141.         END IF
  142.     END IF
  143.  
  144. 'this calc date time diff using Steve' TimeStamp## secs
  145. FUNCTION TimeStampDiff$ (LaterDate$, LaterTime##, EarlierDate$, EarlierTime##)
  146.     secLate## = TimeStamp##(LaterDate$, LaterTime##)
  147.     secEarly## = TimeStamp##(EarlierDate$, EarlierTime##)
  148.     secDiff = secLate## - secEarly##
  149.     'covert to days, hours, minutes, secs I am dropping fraction secs for test
  150.     days = INT(secDiff / 86400)
  151.     secDiff = secDiff - days * 86400
  152.     hours = INT(secDiff / 3600)
  153.     secDiff = secDiff - hours * 3600
  154.     minutes = INT(secDiff / 60)
  155.     secs = INT(secDiff - minutes * 60)
  156.     TimeStampDiff$ = _TRIM$(STR$(days)) + " Days and " + _TRIM$(STR$(hours)) + " Hours, " + _TRIM$(STR$(minutes)) + " Minutes, " + _TRIM$(STR$(secs))
  157.  
  158. ' Steve's latest version
  159. ' https://www.qb64.org/forum/index.php?topic=1638.msg108650#msg108650
  160. FUNCTION TimeStamp## (d$, t##) 'date and timer
  161.     'Based on Unix Epoch time, which starts at year 1970.
  162.  
  163.     m = VAL(LEFT$(d$, 2))
  164.     d = VAL(MID$(d$, 4, 2))
  165.     y = VAL(RIGHT$(d$, 4))
  166.     IF y < 1970 THEN 'calculate shit backwards
  167.         SELECT CASE m 'turn the day backwards for the month
  168.             CASE 1, 3, 5, 7, 8, 10, 12: d = 31 - d '31 days
  169.             CASE 2: d = 28 - d 'special 28 or 29.
  170.             CASE 4, 6, 9, 11: d = 30 - d '30 days
  171.         END SELECT
  172.         IF y MOD 4 = 0 AND m < 3 THEN 'check for normal leap year, and we're before it...
  173.             d = d + 1 'assume we had a leap year, subtract another day
  174.             IF y MOD 100 = 0 AND y MOD 400 <> 0 THEN d = d - 1 'not a leap year if year is divisible by 100 and not 400
  175.         END IF
  176.  
  177.         'then count the months that passed after the current month
  178.         FOR i = m + 1 TO 12
  179.             SELECT CASE i
  180.                 CASE 2: d = d + 28
  181.                 CASE 3, 5, 7, 8, 10, 12: d = d + 31
  182.                 CASE 4, 6, 9, 11: d = d + 30
  183.             END SELECT
  184.         NEXT
  185.  
  186.         'we should now have the entered year calculated.  Now lets add in for each year from this point to 1970
  187.         d = d + 365 * (1969 - y) '365 days per each standard year
  188.         FOR i = 1968 TO y + 1 STEP -4 'from 1968 onwards,backwards, skipping the current year (which we handled previously in the FOR loopp)
  189.             d = d + 1 'subtract an extra day every leap year
  190.             IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  191.         NEXT
  192.         s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  193.         TimeStamp## = -(s## + 24 * 60 * 60 - t##)
  194.         EXIT FUNCTION
  195.     ELSE
  196.         y = y - 1970
  197.     END IF
  198.  
  199.     FOR i = 1 TO m 'for this year,
  200.         SELECT CASE i 'Add the number of days for each previous month passed
  201.             CASE 1: d = d 'January doestn't have any carry over days.
  202.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  203.             CASE 3 'Feb might be a leap year
  204.                 IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
  205.                     d = d + 29 'its a leap year
  206.                     IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
  207.                         d = d - 1 'the year is divisible by 100, and not divisible by 400
  208.                     END IF
  209.                 ELSE 'year not divisible by 4, no worries
  210.                     d = d + 28
  211.                 END IF
  212.             CASE 5, 7, 10, 12: d = d + 30
  213.         END SELECT
  214.     NEXT
  215.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  216.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
  217.         d = d + 1 'add an extra day every leap year
  218.         IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  219.     NEXT
  220.     s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  221.     TimeStamp## = (s## + t##)

According to the website (and screenshot attached), the above is now calculating the dates properly. 

All it took was to change the signs in this area to + instead of -:
Code: [Select]
        'then count the months that passed after the current month
        FOR i = m + 1 TO 12
            SELECT CASE i
                CASE 2: d = d + 28
                CASE 3, 5, 7, 8, 10, 12: d = d + 31
                CASE 4, 6, 9, 11: d = d + 30
            END SELECT
        NEXT

Now, how the flip did I manage to post it with the signs reversed?  And how the flippy flip did I manage to get it sooo close to working, and yet never catch that the results were completely screwed up?  All I can say is, "I'm damn talented!!"

My times are matching the official times, but yours are now off by a day.
Title: Re: Function Timestamp
Post by: bplus on August 24, 2019, 11:05:47 pm
Wow that is way better, but leap years look like they are off 2 days, as if instead of adding one one is subtracted or vice versa...
Title: Re: Function Timestamp
Post by: SMcNeill on August 24, 2019, 11:09:40 pm
Wow that is way better, but leap years look like they are off 2 days, as if instead of adding one one is subtracted or vice versa...

Stupid sign was reversed on them as well.  /sigh. 

Got any explanation on how the heck that could happen??
Title: Re: Function Timestamp
Post by: bplus on August 24, 2019, 11:25:08 pm
Stupid sign was reversed on them as well.  /sigh. 

Got any explanation on how the heck that could happen??

Your evil twin came in a sabotaged your work?

Meds? seems a pretty intelligent and conscious act for meds but I've heard of people driving when sleep walking.

Enemies with forum personnel? Don't even want to go there...

If this is what happened it is truly weird!!

What kind of books do you write? I was just looking tonight when I read your Repo post. I found a Steve McNeill author of GameOn and Rebirth, that you?
Title: Re: Function Timestamp
Post by: SMcNeill on August 24, 2019, 11:39:34 pm
What kind of books do you write? I was just looking tonight when I read your Repo post. I found a Steve McNeill author of GameOn and Rebirth, that you?

Those are mine.  As well as a ton of stuff over at RoyalRoad, Inkitt, and Goodreads.

https://www.royalroad.com/fictions/search?author=Darkbringer&tagsAdd=fantasy&maxPages=20000&status=HIATUS
https://www.inkitt.com/Darkbringer

(Here's hoping the links above work for you.)

Note -- the links above are the unedited versions which I tend to share for promotional purposes, before they're all polished up nice and neat and then published to earn me a little extra hamburger money.  ;)

Title: Re: Function Timestamp
Post by: bplus on August 25, 2019, 12:40:28 am
Wow, so cool! Your avatar too!
Title: Re: Function Timestamp
Post by: bplus on August 25, 2019, 04:17:24 pm
For the record, we are still occasionally a day off, it doesn't start until before 1900, 1899

Here is adjustment to test code that points to the on / off day amounts,
Code: QB64: [Select]
  1. d1970$ = "01-01-1970"
  2. FOR y = 1920 TO 1850 STEP -1
  3.     d$ = "01-01-" + _TRIM$(STR$(y))
  4.     PRINT d1970$; " Minus "; d$
  5.     PRINT DiffDateTime$(DateTime$(d1970$, times$), DateTime$(d$, times$))
  6.     PRINT TimeStampDiff$(d1970$, time##, d$, time##)
  7.     PRINT
  8.     IF y MOD 5 = 0 THEN
  9.         INPUT "OK ... press enter "; w$
  10.         CLS
  11.     END IF
  12.  

The code I am comparing to arrives at the day amounts the same old way regardless of when the earlier date starts and counts day by day up to the later date. I am pretty sure it's correct no matter the earlier date because it is following the leap year rules and is always going in the same time direction but it's likely to be much slower than Steve's where you just do subtraction of seconds of the 2 time dates and convert the secs to days, hours, minutes... but the 2 time dates do need to be correct of course.

Ah I know check New Years 1899 time## = 0 with link.

Update: took me awhile to figure out 24hr option on preference, got it 1899-01-01:
 


The difference is exactly 1 days worth of seconds 86400.


Title: Re: Function Timestamp
Post by: SMcNeill on August 25, 2019, 05:50:56 pm
It's a glitch for negative years divisible by 100 and not 400....

Here's the fix:
Code: QB64: [Select]
  1. _TITLE "Test Steve timeStamp" 'B+ test 2019-08-24
  2. '2019-08-24 Quick test Steve timestamp by comparing DiffDateTime$ to TimeStampDiff$
  3. 'I am just testing day counts
  4.  
  5. SCREEN _NEWIMAGE(600, 760, 32)
  6. times$ = "00:00:00": times## = 0
  7.  
  8. dates$(3) = "08-24-2019": dates$(2) = "01-01-2020": dates$(1) = "01-01-2021": dates$(0) = "01-01-2025"
  9. dates$(4) = "01-01-2019": dates$(5) = "01-01-1970": dates$(6) = "01-01-1815"
  10.  
  11. FOR i = 0 TO 5
  12.     FOR j = i + 1 TO 6
  13.         PRINT dates$(i); " Minus "; dates$(j)
  14.         PRINT DiffDateTime$(DateTime$(dates$(i), times$), DateTime$(dates$(j), times$))
  15.         PRINT TimeStampDiff$(dates$(i), time##, dates$(j), time##)
  16.         PRINT
  17.     NEXT
  18.     INPUT "OK ... press enter "; w$
  19.     CLS
  20. d1970$ = "01-01-1970"
  21. FOR y = 1970 TO 1950 STEP -1
  22.     d$ = "01-01-" + _TRIM$(STR$(y))
  23.     PRINT d1970$; " Minus "; d$
  24.     PRINT DiffDateTime$(DateTime$(d1970$, times$), DateTime$(d$, times$))
  25.     PRINT TimeStampDiff$(d1970$, time##, d$, time##)
  26.     PRINT
  27.     IF y MOD 5 = 0 THEN
  28.         INPUT "OK ... press enter "; w$
  29.         CLS
  30.     END IF
  31.  
  32. ' I used this code for Count Down 2020
  33. 'note: this uses 2 dates and times formatted with DateTime$() Function
  34. FUNCTION DiffDateTime$ (LaterDate$, MinusEarlierDate$)
  35.     es = VAL(MID$(MinusEarlierDate$, 18, 2))
  36.     ls = VAL(MID$(LaterDate$, 18, 2))
  37.  
  38.     em = VAL(MID$(MinusEarlierDate$, 15, 2))
  39.     lm = VAL(MID$(LaterDate$, 15, 2))
  40.  
  41.     eh = VAL(MID$(MinusEarlierDate$, 12, 2))
  42.     lh = VAL(MID$(LaterDate$, 12, 2))
  43.  
  44.     ed = VAL(MID$(MinusEarlierDate$, 9, 2))
  45.     ld = VAL(MID$(LaterDate$, 9, 2))
  46.  
  47.     emm = VAL(MID$(MinusEarlierDate$, 6, 2))
  48.     lmm = VAL(MID$(LaterDate$, 6, 2))
  49.  
  50.     ey = VAL(MID$(MinusEarlierDate$, 1, 4))
  51.     ly = VAL(MID$(LaterDate$, 1, 4))
  52.  
  53.     IF es > ls THEN ls = ls + 60: lm = lm - 1
  54.     DiffDateTime$ = STR$(ls - es) + " secs"
  55.  
  56.     IF em > lm THEN lm = lm + 60: lh = lh - 1
  57.     DiffDateTime$ = STR$(lm - em) + " mins" + DiffDateTime$
  58.  
  59.     IF eh > lh THEN lh = lh + 24: ld = ld - 1
  60.     DiffDateTime$ = STR$(lh - eh) + " hours" + DiffDateTime$
  61.  
  62.     ''did we barrow off day
  63.     IF ld = 0 THEN
  64.         SELECT CASE lmm
  65.             CASE 1: ly = ly - 1: lmm = 12: ld = 31
  66.             CASE 3: IF IsLeapYear(ly) = 1 THEN lmm = 2: ld = 29 ELSE lmm = 2: ld = 28
  67.             CASE 5, 7, 8, 10, 12: lmm = lmm - 1: ld = 30
  68.             CASE 2, 4, 6, 9, 11: lmm = lmm - 1: ld = 31
  69.         END SELECT
  70.     END IF
  71.     'PRINT ly, lmm, ld   ' check target and start
  72.     'PRINT ey, emm, ed
  73.  
  74.     'now count days
  75.     DO
  76.         IF ly = ey THEN
  77.             IF lmm = emm THEN
  78.                 IF ld = ed THEN EXIT DO '  all date numbers match, done calc
  79.             END IF
  80.         END IF
  81.         ed = ed + 1
  82.         cnt = cnt + 1
  83.         IF ed = 29 AND emm = 2 THEN
  84.             'is it leap year
  85.             IF IsLeapYear%(ey) = 1 THEN
  86.                 'pass
  87.             ELSE
  88.                 emm = 3: ed = 1
  89.             END IF
  90.         ELSEIF ed = 30 AND emm = 2 THEN 'must be leap year
  91.             emm = 3: ed = 1
  92.         ELSEIF ed = 31 THEN
  93.             IF emm = 4 OR emm = 6 OR emm = 9 OR emm = 11 THEN
  94.                 emm = emm + 1: ed = 1
  95.             END IF
  96.         ELSEIF ed = 32 THEN
  97.             IF emm = 12 THEN
  98.                 ed = 1: emm = 1: ey = ey + 1
  99.             ELSE
  100.                 ed = 1: emm = emm + 1
  101.             END IF
  102.         END IF
  103.         'PRINT ey, emm, ed, ly; " "; lmm; " "; ld   'Check progress
  104.         '_LIMIT 2
  105.     LOOP
  106.     DiffDateTime$ = _TRIM$(STR$(cnt)) + " Days and" + DiffDateTime$
  107.  
  108. FUNCTION CurrentDateTime$
  109.     CurrentDateTime$ = "    -  -  _  :  :  "
  110.     MID$(CurrentDateTime$, 1, 4) = MID$(DATE$, 7, 4)
  111.     MID$(CurrentDateTime$, 6, 5) = MID$(DATE$, 1, 5)
  112.     MID$(CurrentDateTime$, 12, 8) = TIME$
  113.  
  114. FUNCTION DateTime$ (mm_dd_yy$, hh_mm_ss$)
  115.     DateTime$ = "    -  -  _  :  :  "
  116.     MID$(DateTime$, 1, 4) = MID$(mm_dd_yy$, 7, 4)
  117.     MID$(DateTime$, 6, 5) = MID$(mm_dd_yy$, 1, 5)
  118.     MID$(DateTime$, 12, 8) = hh_mm_ss$
  119.  
  120. FUNCTION IsLeapYear% (yr) 'mod from Pete's calendar this is a very clear calc
  121.     IF yr MOD 4 = 0 THEN
  122.         IF yr MOD 100 = 0 THEN
  123.             IF yr MOD 400 = 0 THEN IsLeapYear = 1
  124.         ELSE
  125.             IsLeapYear = 1
  126.         END IF
  127.     END IF
  128.  
  129. 'this calc date time diff using Steve' TimeStamp## secs
  130. FUNCTION TimeStampDiff$ (LaterDate$, LaterTime##, EarlierDate$, EarlierTime##)
  131.     secLate## = TimeStamp##(LaterDate$, LaterTime##)
  132.     secEarly## = TimeStamp##(EarlierDate$, EarlierTime##)
  133.     secDiff = secLate## - secEarly##
  134.     'covert to days, hours, minutes, secs I am dropping fraction secs for test
  135.     days = INT(secDiff / 86400)
  136.     secDiff = secDiff - days * 86400
  137.     hours = INT(secDiff / 3600)
  138.     secDiff = secDiff - hours * 3600
  139.     minutes = INT(secDiff / 60)
  140.     secs = INT(secDiff - minutes * 60)
  141.     TimeStampDiff$ = _TRIM$(STR$(days)) + " Days and " + _TRIM$(STR$(hours)) + " Hours, " + _TRIM$(STR$(minutes)) + " Minutes, " + _TRIM$(STR$(secs))
  142.  
  143. ' Steve's latest version
  144. ' https://www.qb64.org/forum/index.php?topic=1638.msg108650#msg108650
  145. FUNCTION TimeStamp## (d$, t##) 'date and timer
  146.     'Based on Unix Epoch time, which starts at year 1970.
  147.  
  148.     m = VAL(LEFT$(d$, 2))
  149.     d = VAL(MID$(d$, 4, 2))
  150.     y = VAL(RIGHT$(d$, 4))
  151.     IF y < 1970 THEN 'calculate shit backwards
  152.         SELECT CASE m 'turn the day backwards for the month
  153.             CASE 1, 3, 5, 7, 8, 10, 12: d = 31 - d '31 days
  154.             CASE 2: d = 28 - d 'special 28 or 29.
  155.             CASE 4, 6, 9, 11: d = 30 - d '30 days
  156.         END SELECT
  157.         IF y MOD 4 = 0 AND m < 3 THEN 'check for normal leap year, and we're before it...
  158.             d = d - 1 'assume we had a leap year, subtract another day
  159.             IF y MOD 100 = 0 AND y MOD 400 <> 0 THEN d = d + 1 'not a leap year if year is divisible by 100 and not 400
  160.         END IF
  161.  
  162.         'then count the months that passed after the current month
  163.         FOR i = m + 1 TO 12
  164.             SELECT CASE i
  165.                 CASE 2: d = d - 28
  166.                 CASE 3, 5, 7, 8, 10, 12: d = d - 31
  167.                 CASE 4, 6, 9, 11: d = d - 30
  168.             END SELECT
  169.         NEXT
  170.  
  171.         'we should now have the entered year calculated.  Now lets add in for each year from this point to 1970
  172.         d = d + 365 * (1969 - y) '365 days per each standard year
  173.         FOR i = 1968 TO y + 1 STEP -4 'from 1968 onwards,backwards, skipping the current year (which we handled previously in the FOR loopp)
  174.             d = d + 1 'subtract an extra day every leap year
  175.             IF (i MOD 100) = 0 AND (i MOD 400) <> 0 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  176.         NEXT
  177.         s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  178.         TimeStamp## = -(s## + 24 * 60 * 60 - t##)
  179.         EXIT FUNCTION
  180.     ELSE
  181.         y = y - 1970
  182.     END IF
  183.  
  184.     FOR i = 1 TO m 'for this year,
  185.         SELECT CASE i 'Add the number of days for each previous month passed
  186.             CASE 1: d = d 'January doestn't have any carry over days.
  187.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  188.             CASE 3 'Feb might be a leap year
  189.                 IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
  190.                     d = d + 29 'its a leap year
  191.                     IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
  192.                         d = d - 1 'the year is divisible by 100, and not divisible by 400
  193.                     END IF
  194.                 ELSE 'year not divisible by 4, no worries
  195.                     d = d + 28
  196.                 END IF
  197.             CASE 5, 7, 10, 12: d = d + 30
  198.         END SELECT
  199.     NEXT
  200.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  201.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
  202.         d = d + 1 'add an extra day every leap year
  203.         IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  204.     NEXT
  205.     s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  206.     TimeStamp## = (s## + t##)

This glitch makes perfect sense to me (unlike the swapped signs):

In the second half of the code (where we count forwards), we see this line --         IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400 

And then, it was simply copy/pasted into the top half of the code, as is, which doesn't work.

In the bottom half, we subtract 1970 from our year, and start calculating as if we're working up from year 0.  30 years would be the year 2000.  130 years would be the year 2100...    Years mod 100 = 30, are the years we  need to check to see if they're leap years or not...

In the top half, we work with the date directly, without subtracting that 1970...  1900 is 1900, not -70...  We have to year mod 100 = 0 to check for those special "are they, aren't they" leap years?

A simple change of the remainder in those MOD statements, and all appears to be working correctly.  (Of course, I've thought that before, and some edge case always seems to show up to toss that idea upside down on its head...)

Title: Re: Function Timestamp
Post by: SMcNeill on August 25, 2019, 05:56:09 pm
Unless there's another edge case which seems screwed up, this version seems to finally work for us:

Code: QB64: [Select]
  1. SHELL "https://www.epochconverter.com/"
  2. PRINT "Compare to time stamps generated at the website which popped up in your browser.https://www.epochconverter.com/"
  3.  
  4. CONST MyTimeZone## = 4 * 3600
  5.  
  6.     _LIMIT 1
  7.     CLS
  8.     PRINT TimeStamp(DATE$, TIMER + MyTimeZone) 'Timezone difference with GMT, which is what the webpage sometimes points to.
  9.     '                                           If the times seem off from the website, you'll want to change the timezone
  10.     '                                           offset to match your current time zone.
  11.     PRINT ExtendedTimer 'Unix Epoch Timer based on local time.
  12.     _DISPLAY
  13.  
  14.  
  15. FUNCTION TimeStamp## (d$, t##) 'date and timer
  16.     'Based on Unix Epoch time, which starts at year 1970.
  17.     DIM s AS _FLOAT
  18.  
  19.     l = INSTR(d$, "-")
  20.     l1 = INSTR(l + 1, d$, "-")
  21.     m = VAL(LEFT$(d$, l))
  22.     d = VAL(MID$(d$, l + 1))
  23.     y = VAL(MID$(d$, l1 + 1))
  24.     IF y < 1970 THEN 'calculate shit backwards
  25.         SELECT CASE m 'turn the day backwards for the month
  26.             CASE 1, 3, 5, 7, 8, 10, 12: d = 31 - d '31 days
  27.             CASE 2: d = 28 - d 'special 28 or 29.
  28.             CASE 4, 6, 9, 11: d = 30 - d '30 days
  29.         END SELECT
  30.         IF y MOD 4 = 0 AND m < 3 THEN 'check for normal leap year, and we're before it...
  31.             d = d + 1 'assume we had a leap year, subtract another day
  32.             IF y MOD 100 = 0 AND y MOD 400 <> 0 THEN d = d - 1 'not a leap year if year is divisible by 100 and not 400
  33.         END IF
  34.  
  35.         'then count the months that passed after the current month
  36.         FOR i = m + 1 TO 12
  37.             SELECT CASE i
  38.                 CASE 2: d = d + 28
  39.                 CASE 3, 5, 7, 8, 10, 12: d = d + 31
  40.                 CASE 4, 6, 9, 11: d = d + 30
  41.             END SELECT
  42.         NEXT
  43.  
  44.         'we should now have the entered year calculated.  Now lets add in for each year from this point to 1970
  45.         d = d + 365 * (1969 - y) '365 days per each standard year
  46.         FOR i = 1968 TO y + 1 STEP -4 'from 1968 onwards,backwards, skipping the current year (which we handled previously in the FOR loop)
  47.             d = d + 1 'subtract an extra day every leap year
  48.             IF (i MOD 100) = 0 AND (i MOD 400) <> 0 THEN d = d - 1 'but skipping every year divisible by 100, but not 400
  49.         NEXT
  50.         s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  51.         TimeStamp## = -(s## + 24 * 60 * 60 - t##)
  52.         EXIT FUNCTION
  53.     ELSE
  54.         y = y - 1970
  55.     END IF
  56.  
  57.     FOR i = 1 TO m 'for this year,
  58.         SELECT CASE i 'Add the number of days for each previous month passed
  59.             CASE 1: d = d 'January doestn't have any carry over days.
  60.             CASE 2, 4, 6, 8, 9, 11: d = d + 31
  61.             CASE 3 'Feb might be a leap year
  62.                 IF (y MOD 4) = 2 THEN 'if this year is divisible by 4 (starting in 1972)
  63.                     d = d + 29 'its a leap year
  64.                     IF (y MOD 100) = 30 AND (y MOD 400) <> 30 THEN 'unless..
  65.                         d = d - 1 'the year is divisible by 100, and not divisible by 400
  66.                     END IF
  67.                 ELSE 'year not divisible by 4, no worries
  68.                     d = d + 28
  69.                 END IF
  70.             CASE 5, 7, 10, 12: d = d + 30
  71.         END SELECT
  72.     NEXT
  73.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  74.     FOR i = 2 TO y - 1 STEP 4 'from 1972 onwards, skipping the current year (which we handled previously in the FOR loopp)
  75.         d = d + 1 'add an extra day every leap year
  76.         IF (i MOD 100) = 30 AND (i MOD 400) <> 30 THEN d = d - 1 'but skiping every year divisible by 100, but not 400
  77.     NEXT
  78.     s## = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  79.     TimeStamp## = (s## + t##)
  80.  
  81. FUNCTION ExtendedTimer##
  82.     'Simplified version of the TimeStamp routine, streamlined to only give positive values based on the current timer.
  83.     'Note:  Only good until the year 2100, as we don't do all the fancy calculations for leap years.
  84.     'A timer should work quickly and efficiently in the background; and the less we do, the less lag we might insert
  85.     'into a program.
  86.  
  87.     DIM m AS INTEGER, d AS INTEGER, y AS INTEGER
  88.     DIM s AS _FLOAT, day AS STRING
  89.     day = DATE$
  90.     m = VAL(LEFT$(day, 2))
  91.     d = VAL(MID$(day, 4, 2))
  92.     y = VAL(RIGHT$(day, 4)) - 1970
  93.     SELECT CASE m 'Add the number of days for each previous month passed
  94.         CASE 2: d = d + 31
  95.         CASE 3: d = d + 59
  96.         CASE 4: d = d + 90
  97.         CASE 5: d = d + 120
  98.         CASE 6: d = d + 151
  99.         CASE 7: d = d + 181
  100.         CASE 8: d = d + 212
  101.         CASE 9: d = d + 243
  102.         CASE 10: d = d + 273
  103.         CASE 11: d = d + 304
  104.         CASE 12: d = d + 334
  105.     END SELECT
  106.     IF (y MOD 4) = 2 AND m > 2 THEN d = d + 1 'add a day if this is leap year and we're past february
  107.     d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  108.     d = d + (y + 2) \ 4 'add in days for leap years passed
  109.     s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  110.     ExtendedTimer## = (s + TIMER)
  111.  
Title: Re: Function Timestamp
Post by: SMcNeill on December 27, 2019, 04:06:53 am
Code: QB64: [Select]
  1. FUNCTION ExtendedTimer##
  2.     'modified extendedtimer to store the old day's count, and not have to recalculate it every time the routine is called.
  3.  
  4.     STATIC olds AS _FLOAT, old_day AS _FLOAT
  5.     DIM m AS INTEGER, d AS INTEGER, y AS INTEGER
  6.     DIM s AS _FLOAT, day AS STRING
  7.     IF olds = 0 THEN 'calculate the day the first time the extended timer runs
  8.         day = DATE$
  9.         m = VAL(LEFT$(day, 2))
  10.         d = VAL(MID$(day, 4, 2))
  11.         y = VAL(RIGHT$(day, 4)) - 1970
  12.         SELECT CASE m 'Add the number of days for each previous month passed
  13.             CASE 2: d = d + 31
  14.             CASE 3: d = d + 59
  15.             CASE 4: d = d + 90
  16.             CASE 5: d = d + 120
  17.             CASE 6: d = d + 151
  18.             CASE 7: d = d + 181
  19.             CASE 8: d = d + 212
  20.             CASE 9: d = d + 243
  21.             CASE 10: d = d + 273
  22.             CASE 11: d = d + 304
  23.             CASE 12: d = d + 334
  24.         END SELECT
  25.         IF (y MOD 4) = 2 AND m > 2 THEN d = d + 1 'add a day if this is leap year and we're past february
  26.         d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  27.         d = d + (y + 2) \ 4 'add in days for leap years passed
  28.         s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  29.         old_day = s
  30.     END IF
  31.     IF TIMER < oldt THEN 'we went from 23:59:59 (a second before midnight) to 0:0:0 (midnight)
  32.         old_day = s + 83400 'add another worth of seconds to our counter
  33.     END IF
  34.     oldt = TIMER
  35.     olds = old_day + oldt
  36.     ExtendedTimer## = olds

More efficient version of ExtendedTimer.  This stores our day values and only updates them when necessary.  We really don't need to figure out how many seconds are in today over and over endlessly -- just count them once, and when the clock swaps back to 0:0:0, add 24*60*60 seconds to the count.
Title: Re: Function Timestamp
Post by: EricE on March 27, 2020, 09:24:21 pm
Is the offset due to the local time zone included in the calculation?
Title: Re: Function Timestamp
Post by: EricE on March 27, 2020, 09:34:33 pm
Hi [banned user],
I have started a new thread requesting that the next release of QB64 have a new function which returns the local Time Zone information.
This would be a very useful addition to the QB64 compiler.
EricE
Title: Re: Function Timestamp
Post by: zaadstra on September 29, 2021, 04:37:05 pm
Hi SMcNeill,

I've been running this program (in the green box), and I'm puzzled with the timezone.  My TZ offset now is +02:00 but the program only matches the website when I enter: CONST MyTimeZone## = -2 * 3600

The ExtendedTimer output also is wrong and can't be offset so it seems.

I may have found old obsolete abandoned code ... just wondering ...  I'm building a compare for these date/times: 2019:04:29 13:23:50 (UTC) and 2019:04:29 15:23:49+02:00 (local time notation) ... so still a long way to go. Normally it would just be subtracting one or two hours (DST) but things get awkward when changing days, month or even year....
Title: Re: Function Timestamp
Post by: Pete on September 29, 2021, 07:13:30 pm
Hey Steve, I ran your routine prior to 1970 and got: tihS, just as advertised!

Pete
Title: Re: Function Timestamp
Post by: zaadstra on October 03, 2021, 09:54:14 am
As I ran into an issue with the code (see above), and I wanted to dig a bit deeper to understand things,  I created my own routines. Here are my 2 cents ;-)

I need it to do some tricks with Exiftool so the format is based on that.  It is easy to modify.
There is a routine to convert a normal timestamp to UNIX epoch time, and a routine to convert the other way around.
Time to UNIX is based on the POSIX calculation formula, and UNIX to time is based on an academic paper on Julian dates.

I've put a small loop around it to show current time so you can compare it with the website.  You need to change the timezone tz= to your region.

Code: QB64: [Select]
  1.  
  2. _TITLE "Timestamp and Epoch conversion routines"
  3. ' Configured as Current Time demo loop
  4.  
  5.    CLS
  6.    ' Based on Exiftool  2019:02:05 17:50:30   2019:02:05 18:50:30 +01:00
  7.    tm$ = "2021:10:02 21:00:00"
  8.    'tm$ = "1970:01:02 00:00:00"
  9.    'tm$ = "2319:02:05 17:50:30"
  10.    tm$ = GetNow$
  11.    tz = 2 ' Timezone
  12.  
  13.    IF tz < 0 THEN tzx = ABS(tz): t$ = "-" ELSE tzx = tz: t$ = "+"
  14.    tz$ = " " + t$ + RIGHT$(STR$(100 + tzx), 2) + ":00" ' sorry for the half-hour timezones!
  15.  
  16.    ' date time tm$ to UNIX time
  17.    PRINT: PRINT "Timestamp now   : "; tm$; tz$: PRINT
  18.  
  19.    tm_epoch&& = Epoch&&(tm$) - tz * 3600 ' check: https://www.epochconverter.com/
  20.    PRINT "UNIX epoch time :"; tm_epoch&&
  21.    PRINT
  22.  
  23.    ' UNIX time to date time
  24.    datetime$ = TimeStamp$(tm_epoch&&)
  25.    PRINT "DateTime UTC    : "; datetime$
  26.    datetime$ = TimeStamp$(tm_epoch&& + tz * 3600)
  27.    PRINT "DateTime local  : "; datetime$; tz$
  28.  
  29.    SLEEP 1
  30.  
  31.  
  32.  
  33. FUNCTION Epoch&& (datetime$)
  34.    ' call with date and time argument, format:  "2021:08:09 14:32:14"
  35.    DIM AS _INTEGER64 tm_sec, tm_min, tm_hour, tm_day, tm_month, tm_year, tm_yday
  36.    tm_sec = VAL(MID$(datetime$, 18, 2))
  37.    tm_min = VAL(MID$(datetime$, 15, 2))
  38.    tm_hour = VAL(MID$(datetime$, 12, 2))
  39.    tm_day = VAL(MID$(datetime$, 9, 2))
  40.    tm_month = VAL(MID$(datetime$, 6, 2))
  41.    tm_year = VAL(MID$(datetime$, 1, 4)) - 1900
  42.    tm_yday = INT(275 * tm_month / 9) - (INT((tm_month + 9) / 12) * (1 + INT((tm_year - 4 * INT(tm_year / 4) + 2) / 3))) + tm_day - 30
  43.    Epoch&& = tm_sec + tm_min * 60 + tm_hour * 3600 + (tm_yday - 1) * 86400 + (tm_year - 70) * 31536000 + INT((tm_year - 69) / 4) * 86400 - INT((tm_year - 1) / 100) * 86400 + INT((tm_year + 299) / 400) * 86400
  44.  
  45. FUNCTION TimeStamp$ (tm_epoch&&)
  46.    ' call with argument: UNIX epoch time
  47.    Z& = INT((tm_epoch&& / 86400) + 2440587.5 - 1721118.5)
  48.    R# = (tm_epoch&& / 86400) + 2440587.5 - 1721118.5 - Z&
  49.    G = Z& - .25
  50.    A = INT(G / 36524.25)
  51.    B = A - INT(A / 4)
  52.    year = INT((B + G) / 365.25)
  53.    C& = B + Z& - INT(365.25 * year)
  54.    month = FIX((5 * C& + 456) / 153)
  55.    day = INT(C& - FIX((153 * month - 457) / 5) + R#)
  56.    IF month > 12 THEN year = year + 1: month = month - 12
  57.    tod = R# * 86400
  58.    hh = tod \ 3600
  59.    mm = (tod - hh * 3600) \ 60
  60.    ss = tod MOD 60
  61.    TimeStamp$ = RIGHT$(STR$(10000 + year), 4) + ":" + RIGHT$(STR$(100 + month), 2) + ":" + RIGHT$(STR$(100 + day), 2) + " " + RIGHT$(STR$(100 + hh), 2) + ":" + RIGHT$(STR$(100 + mm), 2) + ":" + RIGHT$(STR$(100 + ss), 2)
  62.  
  63. FUNCTION GetNow$
  64.    GetNow$ = MID$(DATE$, 7, 4) + ":" + MID$(DATE$, 1, 2) + ":" + MID$(DATE$, 4, 2) + " " + TIME$

You may vote for this as 'best answer', LOL !

P.S. thanks to all forummers helping me with insight on variables :-)
Title: Re: Function Timestamp
Post by: bplus on October 03, 2021, 11:06:43 am
@zaadstra

Can yours be used to calculate the difference between 2 dates and times?

Is there a limit to earliest date & time (like start of Gregorian calendar, assuming Gregorian calculations) and future dates like something in year 2050?
Title: Re: Function Timestamp
Post by: zaadstra on October 03, 2021, 11:36:24 am
@zaadstra

Can yours be used to calculate the difference between 2 dates and times?

Is there a limit to earliest date & time (like start of Gregorian calendar, assuming Gregorian calculations) and future dates like something in year 2050?

I think yes,  that's what I intend to use it for.  Although my date/times will be in this age, I have tested working on dates from the year 488 to 2521 and the results checked out with the website.
Title: Re: Function Timestamp
Post by: zaadstra on October 03, 2021, 11:53:27 am
You may remove the loop and setup the tm$ yourself to verify values.  It gets coverted to UNIX time, and then the outcome is converted back.

Gregorian calendar was introduced in the year 1582, and Julian calendar was introduced by Julius Caesar in 46 BC.  Julian date 0 is in the year -4712.... There has been a lot of hassling with the calendars during the ages.  This Julian calculation with a Gregorian sauce on top calculates the current leap years (UNIX to timestamp routine).  You might discuss if that is accurate befoure introducing it before 1582, I did not research that.
Wikipedia and other sites have a lot of information.
Title: Re: Function Timestamp
Post by: zaadstra on October 03, 2021, 05:25:29 pm
I wanted to display difference between epoch times in the Exif program, and since you asked for it @bplus, here it goes:

Code: QB64: [Select]
  1. FUNCTION TimeStampDiff$ (tm_epoch&&)
  2.    ' call with argument: UNIX epoch time difference - a number of seconds - best called with ABS(val1_epoch&& - val2_epoch&&)
  3.    year&& = tm_epoch&& \ 31536000: tm_epoch&& = tm_epoch&& - year&&
  4.    month&& = tm_epoch&& \ 2678400: tm_epoch&& = tm_epoch&& - month&&
  5.    day&& = tm_epoch&& \ 86400: tod = tm_epoch&& - day&& * 86400
  6.    hh = tod \ 3600
  7.    mm = (tod - hh * 3600) \ 60
  8.    ss = tod MOD 60
  9.    TimeStampDiff$ = RIGHT$(STR$(10000 + year&&), 4) + ":" + RIGHT$(STR$(100 + month&&), 2) + ":" + RIGHT$(STR$(100 + day&&), 2) + " " + RIGHT$(STR$(100 + hh), 2) + ":" + RIGHT$(STR$(100 + mm), 2) + ":" + RIGHT$(STR$(100 + ss), 2)

This looks like 0000:00:00 00:12:18 for an epoch diff of 738.