none
vbScript - Accounting for DST in Time Calculations RRS feed

  • Question

  • I've scoured the internet for solutions to performing time addition and difference calcs in vbScript that are sensitive to Daylight Savings Time shifts.

    Many of the solutions expect that you are converting local time to UTC time as of the current offset, but I want to provide times in the future for which I don't know what the offset will be,  e.g.  fromDate + x hours = toDate, where fromDate is not necessarily now().

    I have tried using WbemScripting.SWbemDateTime and this seemed to work great on my laptop, but when I apply the script to a server I get different results! The only thing I can think of is that the version of the library (Wbemdisp.dll, etc.) is different on the two systems.

    Both computers are in EST and have daylight savings time enabled.  They depict DST shifts occurring at the same date and time. 

    I want to accurately depict that the difference in time between the fromDate to the toDate that occur during DST shift  is actually 1 hour greater in the fall than what gets returned from a simple DateDiff of the Local time stamps. This is due to the fact that the time falls back one hour from 02:00 to 01:00 on the date shown. So if I provide a start of 00:59:59 and end of 02:59:59, the hour difference portion should be 3 hours.   If I then add back 3 hours to the fromDate, I should get the toDate.   On the laptop (Win 7 SP1 64Bit) it works.  On the Server (Win 2012 R2) I only get 2 hours difference. When toDate gets converted to UTC,

    Win 7 produces 07:59:59 UTC

    Server 2012 produces 06:59:59 UTC

    Interestingly, when I bump the local toDate further into the future (2018-11-04 06:59:59) both systems behave the same, showing end date of 11:59:59 UTC.

    Here is the script.  Let me know if I am doing something wrong.  Thanks.

    '********************************************************

    fromDate=CDate("2018-11-04 00:59:59")
    toDate=CDate("2018-11-04 02:59:59")

    Set dateTime = CreateObject("WbemScripting.SWbemDateTime")   

    'Convert start and end to UTC
    dateTime.SetVarDate (fromDate)
    dtStartUTC = dateTime.GetVarDate (false)

    dateTime.SetVarDate (toDate)
    dtEndUTC = dateTime.GetVarDate (false)

    'Take the difference
    intHours = DateDiff("h",dtStartUTC,dtEndUTC)

    msgbox "Start UTC Time:  " & dtStartUTC & chr(13) &_
    "End UTC Time: " & dtEndUTC & chr(13) &_
    "Time Difference in Hours: " & intHours,, "Calculate Difference in Time"

    'Now Reverse it

    'Add the difference to the UTC start date to get the UTC end date
    dtEndUTC = DateAdd("h", intHours, dtStartUTC)

    'Convert the end UTC to local
    dateTime.SetVarDate dtEndUTC,false

    toDate = cdate(dateTime.GetVarDate (true))

    msgbox "Start Local Time:  " & fromDate & chr(13) &_
    "End Local Time: " & toDate & chr(13) &_
    "Time Difference in Hours: " & intHours,,"Calculate Target End Date from Start Date"

    set dateTime = nothing

    Friday, June 8, 2018 6:52 PM

All replies

  • To correctly account for DST you must do all calculations in UTC which retains and respects the DST bits.

    To do this you would use PowerShell as it has support for direct date arithmetic with UTC and allows converting UTC to any local time.


    \_(ツ)_/

    Friday, June 8, 2018 7:52 PM
  • Unfortunately, I do not have a choice about what technology to use in order to do the calculation. If you are suggesting that I should invoke powershell as an object in vbScript to do the heavy lifting for me, I guess I can work with that. 

    As you can see though, I am converting to UTC before doing any calcs (except for the cDate which I'm not sure if I can get around).  The conversion to UTC is what is actually different between the two platforms:

    Set dateTime = CreateObject("WbemScripting.SWbemDateTime")   

    dateTime.SetVarDate (toDate)
    dtEndUTC = dateTime.GetVarDate (false)

    dtEndUTC comes up with a different value given the same input.

    Thanks.

    Friday, June 8, 2018 8:15 PM
  • VBS calculations cannot do correct date arithmetic and UTC conversion does not check the DST bit.  DST is not a given in the future.  It changes year-to year and will shift.  You will need tables and the government has not released tables beyond next year.  We cannot guess at what Congress might do.


    \_(ツ)_/

    Friday, June 8, 2018 8:34 PM
  • Of course if the rules change in the future then a calculation I make today will not be valid.  However, when the rules do change, like they did back in the mid 2000s for EST, I expect Microsoft to update the local time zone rules for Windows operating systems ahead of schedule.  According to their blog, they are on top of it for time zones around the world.

    https://blogs.technet.microsoft.com/dst2007/2018/

    Windows is aware of when DST will end and start.  It tells you so when you go to look at the time in the sys tray.

    I expect Windows to be keeping a backend time like Unix Time or Epoch time, that is predictable, and to be able to convert that to a local time given the known rules of DST for each time zone for future dates, and to apply retroactive rules for past dates. 

    Here is my example executed by timeanddate.com. They get it right.

    https://www.timeanddate.com/date/timezoneduration.html?d1=4&m1=11&y1=2018&d2=4&m2=11&y2=2018&h1=0&i1=59&s1=59&h2=2&i2=59&s2=59&

    <form id="hf" name="hf">

    Epoch time Converter also does it correctly showing the epoch time difference in my examples as 

    Start time 1541307599, End time 1541318399, difference = 10800 / 3600 sec/hr = 3

    </form>

    https://www.epochconverter.com/

    Windows is keeping the rules tables already.  I just want to call upon them through vbscript.  The mechanism I describe works on Windows 7 SP1, and it sort of works on Server 2012, if I expand the range straddling the time shift.   So is the answer vbscript can't do it reliably, or that the different versions of Wbemdisp handle the time zone database differently?

    I've noticed the Windows event log can't handle it either.  After a time shift, looking at events that occurred before the shift demonstrate the wrong local time.

    Friday, June 8, 2018 10:47 PM
  • Except that the rules post 2019 are not yet set.  We know that the start and end of DST for the US will change in 2019 and after. We don't have an exact time.  Microsoft only updates the DST clock dates change.  UTC bit cannot be guessed at because it hasn't been set for any date in the future.  The UTC bit is set in Greenwich per time zone and locale.  Greenwich just does what NBS tells them to do.  NBS is controlled by Congress.

    It is s screwy system which is why everyone wants to dump it.  It was invented for political reasons and has become a big headache.

    UTC never reflects DST.  It only has a BIT for DST on the Internet time and on the satellite time. The computer really knows nothing about DST and stores all time as UTC.  It is up to each program to adjust for DST because it I entirely local.  In some locales towns may observe DST or not.  THe Mayor decides and cam change his mind on a whim.

    DO your self a favor and work only in UTC.  Convert at the time of use when the DST flag in the registry has been set.  The UTC to Local methods will then always be correct.


    \_(ツ)_/

    Friday, June 8, 2018 11:30 PM
  • I will present a very simple use case; please tell me if you think I can achieve it vbscript, or powershell, or whatever language. 

    I have an activity in a program for which we capture the local time.  Let's say that local time stamp will be 2018-11-04 00:59:59 which is one hour and  one second before the DST shift in the Eastern time zone.  I can immediately convert that local time stamp to UTC and I'll get 04:59:59   (since at this time of the year we are only -4 UTC) 

    From that timestamp I need to calculate what the local time will be some number of hours into the future.  This is because a particular activity will expire, let's say in 3 hours. I need to finish baking a cake or whatever within 3 hours. I would like to tell the user when they need to be done by.  So I add 3 hours to UTC 04:59:59 to get 07:59:59.  Now I am going to convert this new time back to local time for my user.

    I do not care what congress or what any government agency is going to do in the distant future.   If I keep the windows time patches up to date on the application server with whatever is decided and is addressed by Microsoft, then my calculation will be accurate for the purposes of capturing the start of an activity, and telling the user when they have to finish by for a time in the near future.

    When I convert 07:59:59 UTC to EST for the date 2018-11-04, the offset between the two time zone will be known to have changed from -4 to -5.  The result should be 02:59:59.    00:59:59 + 3 = 02:59:59 since we lose an hour. 

    So I changed my script from the above as shown below, and it works fine now on the server.    :

    '**************************************************

    fromDate=CDate("2018-11-04 00:59:59")

    Set dateTime = CreateObject("WbemScripting.SWbemDateTime")   

    'Convert start to UTC
    dateTime.SetVarDate (fromDate)
    dtStartUTC = dateTime.GetVarDate (false)

    'Add the difference to the UTC start date to get the UTC end date

    'I hard coded the "3" hours below

    dtEndUTC = DateAdd("h", 3, dtStartUTC)

    'Sanity check in UTC

    msgbox dtStartUTC & " & + 3 = " & dtEndUTC

    'Convert the end UTC to local
    dateTime.SetVarDate dtEndUTC,false

    toDate = cdate(dateTime.GetVarDate (true))

    msgbox "Start Local Time:  " & fromDate & chr(13) &_
    "End Local Time: " & toDate & chr(13) &_
    "Time Difference in Hours: " & 3,,"Calculate Target End Date from Start Date"

    set dateTime = nothing

    Wednesday, June 13, 2018 4:33 AM
  • You miss the point of all of this. You take local time.  Add 3 hours.  Convert to UTC.  Send to user.  User gets dt object set to the UTC time and converts back to local time.  All DST and locale will be accounted for.

    You cannot do the users conversion.  The user must convert in their own environment.  That is the whole point of UTC. It is transferrable without you having to know anything about the user.


    \_(ツ)_/

    Wednesday, June 13, 2018 5:52 AM