Convert Time to UTC vbScript

16,147

Solution 1

Here is the solution I ended up implementing at the suggestion of @AardVark71.

I put this in my func.asp file:

<script language="javascript" runat="server">
    function toUtcString(d) {
        var dDate = new Date(d);
        return Math.round(dDate.getTime() / 1000);
    };
</script>

It outputs a timestamp value. Then from anywhere in the classic asp code, I can do this:

response.Write DateAdd("s", toUtcString(cDate("11/11/2012 06:25 PM")), "01/01/1970 00:00:00") 'expect 11/11/2012 10:25:00 PM gmt/utc time
response.Write DateAdd("s", toUtcString(cDate("06/11/2012 06:25 PM")), "01/01/1970 00:00:00") 'expect  6/11/2012  9:25:00 PM gmt/utc time

This (I believe) is simple, and it produces the expected values and fully factors in the DST.

Solution 2

In ASP classic you can mix VBScript and JScript code inside one page. The JScript Date object could be used for local ⇄ UTC date conversion. Complete example:

<%@ language="vbscript" %>
<%
Option Explicit
Dim local_date
Dim utc_date
For Each local_date In Array("11/11/2012 06:25 PM", "06/11/2012 06:25 PM")
    utc_date = local_to_utc(local_date)
    Response.Write "Local: " & local_date & ", UTC: " & utc_date & vbNewLine
Next
For Each utc_date In Array("2012-11-12T02:25:00Z", "2012-06-12T01:25:00+00:00")
    local_date = utc_to_local(utc_date)
    Response.Write "UTC: " & utc_date & ", Local: " & local_date & vbNewLine
Next
%>
<script language="jscript" runat="server">
    function local_to_utc(datestr) {
        // note that this function lets JScript engine parse the date, correctly or otherwise
        var date = new Date(datestr);
        var result = date.getUTCFullYear() + "-" + (date.getUTCMonth() + 1) + "-" + date.getUTCDate() + "T" + date.getUTCHours() + ":" + date.getUTCMinutes() + ":" + date.getUTCSeconds();
        return result.replace(/(\D)(\d)(?!\d)/g, "$10$2") + "Z";
    }
    function utc_to_local(datestr) {
        // note that this function parses only a subset of ISO 8601 date format
        var match = datestr.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{3}))?(?:Z|([-+])(\d{2}):(\d{2}))$/);
        var offset = match[8] ? (match[8] === "+" ? 1 : -1) * (match[9] * 60 + match[10] * 1) : 0;
        var date = new Date(Date.UTC(match[1], match[2] - 1, match[3], match[4], match[5] - offset, match[6], match[7] || 0));
        var result = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
        return result.replace(/(\D)(\d)(?!\d)/g, "$10$2");
    }
</script>

Expected result:

And the output when executed on a server using PST/PDT time:

Local: 11/11/2012 06:25 PM,       UTC:   2012-11-12T02:25:00Z
Local: 06/11/2012 06:25 PM,       UTC:   2012-06-12T01:25:00Z
UTC:   2012-11-12T02:25:00Z,      Local: 2012-11-11 18:25:00
UTC:   2012-06-12T01:25:00+00:00, Local: 2012-06-11 18:25:00
Share:
16,147
GWR
Author by

GWR

Updated on June 08, 2022

Comments

  • GWR
    GWR almost 2 years

    I have the following function which does fine at converting current time to UTC time.

    Function toUtc(byVal dDate)
        Dim oShell : Set oShell = CreateObject("WScript.Shell")
        toUtc = dateadd("n", oShell.RegRead("HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias"), cDate(dDate))
    End Function
    

    However, I am thinking that this does not adequately handle conversion of future or historical dates to UTC, since the function would need to know the offset of the server's timezone at the time of the date that is being converted, and whether or not it was during daylight savings time or not.

    How can I get around this?

    I am using vbScript/Classic ASP on windows server with IIS7.5

    To clarify, this has nothing to do with formatting the date. It is all about converting to UTC from the server timezone for historical dates. During Daylight savings time, the offset will be off by 60 minutes if I try to convert a datetime which occurred in standard time.

    For example:

    Lets say that today, 2013-02-19 (non daylight-savings time), I want to covert a timestamp from say, 2008-06-05 (during daylight savings period) from PDT (my server timezone) to UTC. using the method in my function will give me a value which is 60 minutes off from the correct value (because the CURRENT time is PST (not PDT), the offset will be incorrect for that historical date).

    In other words, the timezone offset of the input date could be UTC-7 or UTC-8 depending on whether or not DST was observed on that particular date. I need to calculate the correct UTC date for the input date and I need the code to work whether or not DST is observed on current date.

  • GWR
    GWR about 11 years
    Yes you are missing the main issue - say today, 2013-02-19, I want to covert a timestamp from say, 2008-06-05 (during daylight savings time) from PDT (my server timezone) to UTC. using the method you described will give me a value which is 60 minutes off from the correct value (because the CURRENT time is PST (not PDT), the offset will be incorrect for that historical date).
  • Panayot Karabakalov
    Panayot Karabakalov about 11 years
    Wait a min, why you using CURRENT time? I thought you can flesh out the idea from my bone and finish the rest, or you need more help?
  • GWR
    GWR about 11 years
    What I meany by "current" is that your wmi query returns the offset at time you request it, which could be different than the offset at the datetime you are trying to convert.
  • Panayot Karabakalov
    Panayot Karabakalov about 11 years
    Ok, I see, may bad is that I trust too much on MS :)
  • GWR
    GWR about 11 years
    Thanks for all of the effort.. your last iteration looks like it could do the trick. I ended up going with a different solution using javascript. Will post below.
  • ulluoink
    ulluoink almost 11 years
    this won't work for timestamps with values greater then subtype Long. e.g. DateAdd("s", toUtcString(cDate("01/01/2060 06:25 PM")), "01/01/1970 00:00:00")
  • Leif Neland
    Leif Neland over 8 years
    This does not work for ISO8601 dates. Run at server, new Date("2015-08-27T12:28:51") return NaN Run at client Thu Aug 27 2015 11:58:16 GMT+0200 I wanted to convert UTC to local time.
  • GWR
    GWR almost 6 years
    @Leif Neland - That is a trivial date format issue, and not a problem with the function above.
  • GWR
    GWR almost 6 years
    Interesting. I will run some tests on this later today. Will get back to you
  • AlexLaforge
    AlexLaforge almost 6 years
    Works perfectly, and avoids the needs to use Server.CreateObject("WbemScripting.SWbemDateTime"). Moreover, it is elegant in that it allows to include jScript code directly inside the page.
  • GWR
    GWR over 4 years
    These are nice, but unfortunately, when converting historical dates, they don't address whether or not DST was in effect at the time of the historical date (unless I am missing something or misunderstand your code)
  • Stephen R
    Stephen R over 4 years
    Ouch. You are correct. And that’s a difficult one to calculate because so many different locales have different rules
  • GWR
    GWR over 4 years
    Yes. Depending on specific use cases we've done things in the past where we had to have a lookup table (or whatever data structure you prefer working with) which had historical date ranges and DST start/end dates which had to be factored in to historical conversions. Now in any new software or code I write, I usually try to save values as utc and ALSO store the source timezone/offset/dst info, just so that it's there for any future conversion work that may be needed. Overkill? Maybe. But I find this a tough problem to get around any other way.
  • Stephen R
    Stephen R over 4 years
    It’s always easier to do it right in the first place! ;-)
  • Stephen R
    Stephen R over 4 years
    It would be interesting to try to create an ASP class that does this for us. Basically add "time zone" data to the Date class. I'd say three elements: timestamp, time zone name, and the actual offset. Add serialization/deserialization functions and you could maybe store it all in one field. For compatibility use the same Time Zone names as, say, PHP? Maybe even an encapsulated routine for calculating/converting historic offsets based on Time Zone. Hmmm. Then of course build a time machine and do this twenty years ago!
  • GWR
    GWR over 4 years
    This is a great idea actually. Would save the latency created by DB lookups for the historical conversion stuff. Next time I need to deal with this, I may just go this route.
  • Stephen R
    Stephen R over 4 years
    If you do it, please post the class online! This could be really useful to anyone working with Classic ASP. (Or did you mean the time machine? Can I borrow it? I’ll give it back ten minutes ago)
  • Stephen R
    Stephen R over 4 years
    The serialized strings in the DB should still be reasonably sortable/filterable if alphabetical==chronological. You’d have to always make the timestamp UTC, (the deserialize function would reapply the offset as needed). Maybe even best in this case to make the timestamp a no-dashes Integer