I am using this code to determine EPOCH timestamp at midnight for a given date (ldDate).
ltFoxTime = getUtcTime(DTOT(ldDate))
lnTimeStamp = ltFoxTime - DATETIME(1970, 1, 1, 0, 0, 0)
I'm having some troubles now that my locale is no longer in daylight savings time. I used a UTC calulator (https://www.epochconverter.com/) to find the EPOCH timestamp for my locale (US Eastern) at midnight on 05 November just before the time change, I get: 1509854400. When I use my routine, I get the time for 1 am: 1509858000.
There's a bug in GetUtcTime()
that doesn't deal daylight savings time correctly for non-current dates.
It's been fixed by using .NET and wwDotnetBridge to do the two way conversions.
For more info and a patch check out this thread:
The patch file is here which includes updates to wwutils and an updated wwDotnetBridge.dll that includes the required support functions.
+++ Rick ---
I believe I have the fixes installed properly. My understanding is that these fixes should have corrected Rob's code from the related case. But, using his example, the time stamp still comes back one hour off - even after the update. So, I've instituted the code below to determine the time zone offset needed to adjust for the bug in getUtcTime.
ltTime = DTOT(ldDate)
loResult = CREATEOBJECT("empty")
ADDPROPERTY(loResult, "Time", ltTime)
lcJSON = poSer.Serialize(loResult)
loResult = poSer.DeserializeJSON(lcJSON)
lnTZOffset = loResult.Time - ltTime
If you're using the updated files you should be able to run this:
goJSON = CREATEOBJECT("wwJsonSerializer")
goJson.AssumeUtcDates = .F.
loResult = CREATEOBJECT("empty")
ltTime = {09/01/2017 21:32:50}
ADDPROPERTY(loResult, "Time", ltTime)
?loResult.Time
lcJSON = goJSON.Serialize(loResult)
?lcJSON
loResult = goJSON.DeserializeJSON(lcJSON)
?loResult.Time
and get the same value back as you started for the current date and a date that falls in DST.
If that's not working then you're not running those latest files.
Note also that if you have loSer.AssumeUtcDates = .T.
only the serialization is affected. Deserialization will always return a local date.
+++ Rick ---
My apologies. I thought for sure that I did a re-compile after moving in the new code - but, I'm sure I missed that step now.
Yes, now this code returns the same date/time. Is there a way for me to get the epoch timestamp?
I got it now. I'm grabbing the time zone offset from the serializer and factoring that into my epoch calculation.
I'm not sure what you mean by the epoch timestamp. You can get local time (adjusted for DST) or Universal (UTC) time of any date via getUtcTime()
or fromUtcTime()
.
+++ Rick ---
Uh... it turns out I didn't update GetUtcTime()
and FromUtcTime()
in the patch zip file. I've updated it again - those functions now use wwDotnetBridge.
+++ Rick ---
Thanks so much - but I ran into a slight problem. I got the error that __GetwwDotnetBridge does not exist. When I remove the underscores, it works fine and the getutctime bug is corrected.
Ah yes. Thanks for catching that. __GetwwDotnetBridge() function is a special helper that helps load wwdotnetBridge without explicitly requiring a reference to wwDotnetBridge. After some more thought on this this is really not necessary since wwDotnetBridge is required no matter what so if not available we'll just have the code fail.
IAC, I've updated again and it should now just work if you do:
CLEAR
SET PROCEDURE TO
DO wwdotnetBridge
DO wwAPI
ltCurrent = DATETIME()
? "Current: ",ltCurrent
ltTime = GetUtcTime(ltCurrent)
? "UTC: ",ltTime
? "Current (from Utc): ",FromUtcTime(ltTime)
+++ Rick ---
Works great - thank you for getting this resolved so quickly.
Hi Rick -
You also have this code in wwutils -
FUNCTION FormatValue(lvValue,lcFormatString)
LOCAL loBridge
IF ISNULL(lvValue)
RETURN "null"
ENDIF
loBridge = __GetwwDotnetBridge()
and
************************************************************************
* FormatString
****************************************
*** Function: Uses a string template to embed formatted values
*** into a string.
*** Assume:
*** Pass:
*** Return:
************************************************************************
FUNCTION FormatString(lcFormat, lv1,lv2,lv3,lv4,lv5,lv6,lv7,lv8,lv9,lv10)
LOCAL lnParms, loBridge
lnParms = PCOUNT()
loBridge = __GetwwDotnetBridge()
Can I assume that this is the replacement?
loBridge = EVALUATE("GetwwDotnetBridge()")
No those are broken - I have them fixed here. Just remove the underscores for now. The final versions use:
loBridge = EVALUATE("GetwwDotnetBridge()")
The reason for this is to avoid having wwUtils.prg
automatically pull in wwdotnetbridge.prg
when referencing, so if you don't use functions that require wwDotnetBridge you don't have to take the dependency.
More and more I'm integrating .NET functionality though and it's already pretty much required for Web Connection but not yet for the Client Tools.
+++ Rick ---