Convert between arbitrary timezones - vba

I'm trying to find a simple yet robust way to convert time between arbitrary time zones.
This: http://www.cpearson.com/excel/TimeZoneAndDaylightTime.aspx explains only how to convert betwen my (current) TZ and another TZ.
Those two SO articles (Getting Windows Time Zone Information (C++/MFC) and How do you get info for an arbitrary time zone in Windows?) talk about getting the information from the registry.
That sounds a bit too convoluted and time-consuming; moreover, it appears that Windows stores TZs in their "full names" (such as (UTC-08:00) Pacific Time (US & Canada)) and I'd rather refer to TZs using abbreviations (such as EDT). Moreover, relying on Windows registry could also be unsafe: different users might have different versions and some might not be up to date. That would mean a report run by two persons might provide two different results!
Is there a simpler way that will also be robust? Writing a lookup table could work for some time but then it will be broken when a government decides to abolish DST or change anything else.
Maybe get a list of TZs from Internet and parse it? Would that be safe enough?
Update 1
I've made my research and explored the possibilities, but this problem is not as trivial as it might seem. If you think that the function shall look like bTime = aTime + 3, then please reconsider. Timezones and DSTs are in a state of constant flux.
Read this for reference: list of pending / proposed timezone changes. Note that some countries are actually changing their timezones, not just DST settings! And Brazil changed the date on which they change their clocks to winter time! A static lookup table would be broken very quickly by all those changes.
Update 2
I'm not looking into a quick and dirty hack, I can come up with that myself. I'm not wanting to write something and forget about it; I'd like to create a function once that could be safely used by other people for different internal projects without the maintenance nightmare. Hard-coding constants that are known to change once in a while is a very bad software design (think Y2K bug caused by a very, very old piece of code).
Update 3
This database looks good (although I'm not sure if it's stable enough): https://timezonedb.com/api. They even have a TZ conversion call - exactly what I need! I will probably try to parse XML from VBA and share my results.

The API at https://timezonedb.com/references/convert-time-zone is indeed a great place to get the correct worldwide time, timezone, and timezone-offset between two locations, taking into account past/future Daylight Savings changes.
A problem with your suggested method of specifying only the Time Zone Abbreviations (such as "convert PST to EST") is that this API takes your zones literally, even if they are incorrect.
So, if Toronto is currently on EDT but you specify EST, you'll probably get the incorrect time. Using "full names" like (UTC-08:00) Pacific Time (US & Canada) would have the same issue.
A way around that is to specify the time zone names like America/Vancouver (as listed here), or else specify the city, country and/or region name with the appropriate parameters.
I wrote a function to figure it out but it only applies to certain countries (see further down).
What time was it in Toronto last Halloween at 11:11pm Vancouver time?
http://api.timezonedb.com/v2/convert-time-zone?key=94RKE4SAXH67&from=America/Vancouver&to=America/Toronto&time=1509516660
Result: (Default is XML but JSON is also available.)
<result>
<status>OK</status>
<message/>
<fromZoneName>America/Vancouver</fromZoneName>
<fromAbbreviation>PDT</fromAbbreviation>
<fromTimestamp>1509516660</fromTimestamp>
<toZoneName>America/Toronto</toZoneName>
<toAbbreviation>EDT</toAbbreviation>
<toTimestamp>1509527460</toTimestamp>
<offset>10800</offset>
</result>
Getting the data programmatically:
There are plenty of options and lookup methods you will have to decide upon, but here's one example using a VBA Function:
What will be the time difference between Vancouver & Berlin on Christmas Day?
Input Time: 2018-12-25 00:00:00 = Vancouver Local Unix time 1545724800
Function GetTimeZoneOffsetHours(fromZone As String, _
toZone As String, UnixTime As Long) As Single
Const key = "94RKE4SAXH67"
Const returnField = "<offset>"
Dim HTML As String, URL As String
Dim XML As String, pStart As Long, pStop As Long
URL = "http://api.timezonedb.com/v2/convert-time-zone?key=" & key & _
"&from=" & fromZone & "&to=" & toZone & "&time=" & UnixTime
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", URL, False
.Send
XML = .ResponseText
End With
pStart = InStr(XML, returnField)
If pStart = 0 Then
MsgBox "Something went wrong!"
Exit Function
End If
pStart = pStart + Len(returnField) + 1
pStop = InStr(pStart, XML, "</") - 1
GetTimeZoneOffsetHours = Val(Mid(XML, pStart, pStop - pStart)) / 60
End Function
Sub testTZ()
Debug.Print "Time Zone Offset (Vancouver to Berlin) = " & _
GetTimeZoneOffsetHours("America/Vancouver", _
"Europe/Berlin", 1545724800) & " hours"
End Sub
Unix/UTC Timestamps:
Unix time is defined as "the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970."
You can convert times between Unix and/or UTC or Local time at: epochconverter.com ... the site also has conversion formulas for several programming languages.
For example, the formua to convert Unix time to GMT/UTC in Excel is:
=(A1 / 86400) + 25569
You could also download static files (in SQL or CSV format) here instead of caling the API, and the page also has sample queries. However use caution: it's easier to make mistakes with Daylight Savings (as mentioned above).
I made a dummy account to get the "demo" used in the examples, but you should get your own (free) key for long-term use. (I'm not responsible if it gets locked out from over-use!)
An good alternative Time Zone API is Google Maps Time Zone API. The difference is that you specify Latitude & Longitude. It seems to work just fine without a key You'll need to register for a key.
What will the Time Zone Offset be on June 1st at the White House?
https://maps.googleapis.com/maps/api/timezone/json?location=38.8976,-77.0365&timestamp=1527811200&key={YourKeyHere}
Result:
{
"dstOffset" : 0,
"rawOffset" : -18000,
"status" : "OK",
"timeZoneId" : "America/Toronto",
"timeZoneName" : "Eastern Standard Time"
}
The Offset will be -18000 seconds (-5 hours).
Determining when Daylight Savings is in effect
Below is a function I put together so I could "trust" the Daylight Savings (DST) values I was getting from a different API, however (as discussed by others) the rules have no pattern plus are constantly changing country by country, even town by town in some parts of the world, so this only will work in countries where:
DST begins on the Second Sunday of March every year
DST end on the First Sunday of November every year
The applicable countries are Bahamas, Bermuda, Canada, Cuba, Haiti, St. Pierre & United States. (Source: Daylight saving time by country**)
Function IsDST(dateTime As Date) As Boolean
'Returns TRUE if Daylight Savings is in effect during the [dateTime]
'DST Start (adjust clocks forward) Second Sunday March at 02:00am
'DST end (adjust clocks backward) First Sunday November at 02:00am
Dim DSTStart As Date, DSTstop As Date
DSTStart = DateSerial(Year(dateTime), 3, _
(14 - Weekday(DateSerial(Year(dateTime), 3, 1), 3))) + (2 / 24)
DSTstop = DateSerial(Year(dateTime), 11, _
(7 - Weekday(DateSerial(Year(dateTime), 11, 1), 3))) + (2 / 24)
IsDST = (dateTime >= DSTStart) And (dateTime < DSTstop)
End Function
And a couple examples of how I could use function IsDST*:
Public Function UTCtoPST(utcDateTime As Date) As Date
'Example for 'PST' time zone, where Offset = -7 during DST, otherwise if -8
If IsDST(utcDateTime) Then
UTCtoPST = utcDateTime - (7 / 24)
Else
UTCtoPST = utcDateTime - (8 / 24)
End If
End Function
Function UTCtimestampMStoPST(ByVal ts As String) As Date
'Example for 'PST', to convert a UTC Unix Time Stamp to 'PST' Time Zone
UTCtimestampMStoPST = UTCtoPST((CLng(Left(ts, 10)) / 86400) + 25569)
End Function
* Note that function IsDST is incomplete: It does not take into account the hours just before/after IsDST takes actually effect at 2am. Specifically when, in spring, the clock jumps forward from the last instant of 01:59 standard time to 03:00 DST and that day has 23 hours, whereas in autumn the clock jumps backward from the last instant of 01:59 DST to 01:00 standard time, repeating that hour, and that day has 25 hours ...but, if someone wants to add that functionality to update the function, feel free! I was having trouble wrapping my head around that last part, and didn't immediately need that level of detail, but I'm sure others would appreciate it!
Finally one more alternative is an API that I use to for polling current/future/historical weather data for various purposes — and also happens to provide Timezone Offset — is DarkSky.
It queries by latitude/longitude and is free (up to 1000 calls/day) and provides "ultra-accurate weather data" (more-so in the USA, where it predicts weather down to the minute and to the square-yard! — but quite accurate I've seen for the unpredictable Canadian West Coast Canada!)
Response is in JSON only, and the very last line is Time Zone Offset versus UTC/GMT time.
DarkSky Sample Call:
https://api.darksky.net/forecast/85b57f827eb89bf903b3a796ef53733c/40.70893,-74.00662
It says it's supposed to rain for the next 60 hours at Stack Overflow's Head Office. ☂
...but I dunno, it looks like a pretty nice day so far! ☀
(flag)

Im afraid anything to do with timezones is never a simple task (ask any web designer and they will say it is a massive challenge)
there are 2 ways to solve your problem
1) The Easy way - Create a central list which all other workbooks are linked to. This can be saved on SharePoint or on a shared drive, then all you have to do is update this one table
2) The hard way - Use a website API to get the latest timezone data. https://www.amdoren.com/ is a good site, you can get a free API key by signing up. The only issue is you then have to parse the Json file from the website. This isn't easy but if you google "vba parse json" you will find some solutions (it generally requires importing some libraries and using other peoples code as a starting point)
Hope you find the right solution, and if you do might be worth sharing it as im sure there will be others with same issue.

Related

Guess if a user will make or not a conversion

My friends,
In the past couple of years I read a lot about AI with JS and some libraries like TensorFlow. I have great interest in the subject but never used it on a serious project. However, after struggling a lot with linear regression to solve an optimization problem I have, I think that finally I will get much better results, with greater performance, using AI. I work for 12 years with web development and lots of server side, but never worked with any AI library, so please, have a little patience with me if I say something stupid!
My problem is this: every user that visits our platform (website) we save the Hour, Day of the week, if the device requesting the page was a smartphone or computer... and such of the FIRST access the user made. If the user keeps visiting other pages, we dont care, we only save the data of the FIRST visit. And if the user anytime does something that we consider a conversion, we assign that conversion to the record of the first access that user made. So we have almost 3 millions of lines like this:
SESSION HOUR DAY_WEEK DEVICE CONVERSION
9847 7 MONDAY SMARTPHONE NO
2233 13 TUESDAY COMPUTER YES
5543 19 SUNDAY COMPUTER YES
3721 8 FRIDAY SMARTPHONE NO
1849 12 SUNDAY COMPUTER NO
6382 0 MONDAY SMARTPHONE YES
What I would like to do is this: next time a user visits our platform, we wanna know the probability of that user making a conversion. If a user access now, our website, depending on their device, day of week, hour... we wanna know the probability of that user making a future conversion. With that, we can show very specific messages to the user while he is using our platform and a different price model according to that probability.
CURRENTLY we are using a liner regression, and it predicts if the user will make a conversion with an accuracy of around 30%. It's pretty low but so far, it's the best we got it, and this linear regression generates almost 18% increase in conversions when we use it to show specific messages/prices to that specific user compaired to when we dont use it. SO, with a 30% accuracy our linear regression already provides 18% better conversions (and with that, higher revenues and so on).
In case you are curious, our linear regression model works like this: we generate a linear equation to every first user access on our system with variables that our system tries to find in order to minimize error sqr(expected value - value). Using the data above, our model would generate these equations below (SUNDAY = 0, MONDAY = 1...COMPUTER = 0, SMARTPHONE = 1... CONVERSION YES = 1 and NO = 0)
A*7 + B*1 + C*1 = 0
A*13 + B*2 + C*0 = 1
A*19 + B*0 + C*0 = 1
A*8 + B*6 + C*1 = 0
A*12 + B*0 + C*1 = 0
A*0 + B*1 + C*0 = 1
So, our system find the best A, B and C that generates the minimizes error. How can we do that with AI? If possible, it would be nice if we could use TensorFlow or anything with JS! I know there are several AI models, and I have no idea which one would best fit what we need!

Need a count for a field from different timezones (have multiple fields from .csv uploaded file)

I am little confused, as i have some events ingesting from .csv file in splunk from different different timezones china, pacific, eastern, europe etc...
I have fields like start time, end time, TimeZone, TimeZoneID, sitename, conferenceID & hostname.....etc
for your info(conferenceID=131146947830496273, 130855971227450408......)
was wondering if i have to do a ".......|stats count of conferenceID" for particular time interval(ex., 12:00 pm to 15:00 pm today ) by sitting on pacific timezone, using the start time and end time from the events search should collect all events sorting from there originating timezones time interval but not the taking splunk timezone time interval.
below are some samples of logs which I have
testincsso,130878564690050083, Shona,"GMT-07:00, Pacific (San Francisco)",4,06/17/2019 09:33:17,06/17/2019 09:42:23,10,0,0,0,0,0,0,9,0,0,1,0,0,1,1
host = usloghost1.example.com sourcetype =webex_cdr
6/17/19
12:29:03.060 AM
testincsso,129392485072911500,Meng,"GMT+08:00, China (Beijing)",45,06/17/2019 07:29:03,06/17/2019 07:59:22,31,0,0,0,0,0,0,0,0,30,1,1,0,0,1
host = usloghost1.corp.example.com sourcetype = webex_cdr
6/17/19
12:19:11.060 AM
testincsso,131121310031953680,sarah ward,"GMT-07:00, Pacific (San Francisco)",4,06/17/2019 07:19:11,06/17/2019 07:52:54,34,0,0,0,0,0,0,0,0,34,3,3,0,0,2
host = usloghost1.corp.example.com sourcetype = webex_cdr
6/17/19
12:00:53.060 AM
testincsso,130878909569842780,Patrick Janesch,"GMT+02:00, Europe (Amsterdam)",22,06/17/2019 07:00:53,06/17/2019 07:04:50,4,0,0,0,0,0,0,4,0,2,3,2,0,1,2
host = usloghost1.corp.example.com sourcetype = webex_cdr
update:
there is 2 fields in the events start time and end time for every conference it held in there local timezone(event originating TZ).
also _time refers the splunk time which I don't need in this case. what I need is there is date_hour, date_minutes, date_seconds...etc which shows events local timezone time(china, europe, asia...etc).
so when i sit here pacific TZ and try searching for
index=test "testincsso" | stats count(conferenceID) by _time
taking timeinterval last 4 hours then the output should display the count of Cenferences by taking the count from all events by comparing with there local TZ's time for last 4 hours.
so do I need to use "| eval hour = strftime(_time,"%H")" or "| eval mytime=_time | convert timeformat="%H ctime(mytime)" before stats.
thanks
-also changing timepicker default behavior may give correct results.
I have events with fields "start time" and "end time" from different TZ. so when I try to search events ex., date range "06-16-2019" using time-picker I should get all events by seeing the field "start time" in events not the "_time" of Splunk.
I want change my splunk time picker default behavior and gives output by sieng events fields(ex., "start time" & "end time". below the query I changed in source xml.
index=test sourcetype=webex] "testinc" | eval earliest = $toearliest$ | eval latest=if($tolatest$ < 0, now(),$tolatest$) | eval datefield = strptime($Time$, "%m/%d/%Y %H:%M:%S")|stats count(Conference)
If you have any control over how the logs are generated, it's best to include the time zone as part of the timestamp. For example, "06/17/2019 07:00:53+0200". Then Splunk can easily convert the time.
If that's not an option, perhaps you can specify the time zone when the logs are read. Assuming each log is stored on a system in the originating time zone, the props.conf stanza for the Universal Forwarder should include a TZ attribute telling Splunk where in the world the log is from.
If this doesn't help, please edit your question to say what problem you are trying to solve.

Query Access from Excel: Variable Parameters

I've been doing in depth, functional area dashboards in excel that are refreshed upon end-user command of the 'refresh all' button. The only problem I am running into is refreshing daily production when it is past midnight, thus turning access' back end query of 'date()' to, well, the current day at midnight.
This has been the condition I want to work properly: I want everything >= 5 AM for either today or previous day based on the NOW time.
WHERE start_time >=
(iif(timevalue(now()) between #00:00# and #4:59#,date()-1,date()))
AND timevalue(start_time) >= #5:00#;
The thing is that it is returning in such an extremely slow rate.
I don't think I've ever waited for it to complete. I'm not sure if its calculating this logic on every record involved in the back end table or not, which would explain the lock up.
I really want to avoid building any logic dynamically as I am simply using Excel to call upon this Access query through the query wizard.
I would hate to have to resort to an access button triggering a module to build the query dynamically and then focus the excel window and refresh.
It would be nice to create an object on, say, a [Form]! but that is only useful when the form is active.. even then the SQL rejects any sub-calculations within the object of the form.
Any thoughts?
I believe parsing down to the mathematical equivalent of a boolean HOUR(Now)<5 should speed things up considerably.
WHERE start_time >= (Date + (Hour(Now)<5) + TimeSerial(5, 0, 0))
A boolean True is considered -1.
This seems to be working; I needed a ' ' to concat times correctly. Gustav brought up the 'between' and 'or'; this is working fine on my offline test db - I will mark this way down as a possible solution. I also added seconds in order to capture last minute data of 23:59:00 to 23:59:59
WHERE
iif(timevalue(now()) Between #00:00# And #4:59#,
(start_time
Between Date()-1&' '&#05:00# And Date()-1&' '&#23:59:59#)
OR
(start_time Between date()&' '&#00:00# And date()&' '&#23.59:59#),
(start_time Between date()&' '&#00:00# And date()&' '&#23.59:59#));
I just now need to build into it the now() condition in an iif statement to decided which condition to exectute!
You can use:
WHERE start_time
(Between Date() - 1 + #05:00:00# And Date() - 1 + #23:59:59#)
Or
(Between Date() + #05:00:00# And Date() + #23:59:59#)

EWS Managed API: Fetch emails by search filter on DateTimeReceived

While searching for items in the inbox that have been received after a particular time frame (as mentioned in the code below). It searches for the date but it is also returning the email with the specified timestamp. I want the emails only after the specified timestamp.
SearchFilter greaterthanfilter = new SearchFilter.IsGreaterThan(ItemSchema.DateTimeReceived,
Convert.ToDateTime(lastUploadedEmailtimeStamp));
mailItems = inbox.FindItems(greaterthanfilter, view);
Not sure if anyone has faced any similar issues? Basically I want to search for items that were received after a particular mm/dd/yyyy hh:mm:ss.
Exchange stores the datetimes with a precision down to the Millisecond, EWS only give you a precision on datetimes to the second however the Searchfilters do have a precision of milliseconds with Date time. So if you datetime stamps your using only have a precision of seconds then you need to use something like this eg where you wanted all email that was received after 7:43 and 8 seconds
SearchFilter sfs = new SearchFilter.IsGreaterThan(ItemSchema.DateTimeReceived, DateTime.ParseExact("2014/12/29 07:43:08.999", "yyyy/MM/dd HH:mm:ss.fff", null));
FindItemsResults<Item> femaa = service.FindItems(WellKnownFolderName.Inbox,sfs, iItemView);
If you want to look at the actual precision on your messages you need to use a MAPI editor like OutlookSpy of MFCMapi. You can then look at the PT_Systime value which are FileTime "8 bytes; a 64-bit integer representing the number of 100-nanosecond intervals since January 1, 1601" see http://msdn.microsoft.com/en-us/library/ee157583(v=EXCHG.80).aspx
Cheers
Glen

Calculate end date based on # of days and start date

I am working on script where users can make certain type of orders. Now when users make an order they can choose how long they wont it to last in # of days. Once the order is placed I need to approve their order and that approval date is recorded inside my database. Now what I need is to show inside their user panel how much days their package will last since the day of my approval. So for example if I approved their order September 08, 2013 and they choosed for the order to last 7 days, I wont them to see inside they panel for every next day they login how much days they have left, so 7days, 6days, 5days, etc... all the way to "0 Days" when they come to their panel on September 16, 2013.
I have following variables for those two values:
$row_ordersResults['date'] - the date I approved the order
$row_ordersResults['drip_feed'] - # of days they wont for their order to last
I did tried to lots of combinations by myself but I am totally stuck with this and cant make it work.
Thanks for help!
The libraries at momentjs.com is pretty cool. But if you just wanted something simple to calculate the "date difference" between two time values, there is a relatively simple way to do it. I assume you wanted it done in Javascript.
All you need to do is to clear out the hour/minute/second/millisecond fields of the two dates, calculate their differences in days. Put the script below in any web browser and you'll see how it works.
<script>
function foo() {
var d1 = new Date(2013, 8, 12, 13, 40, 1, 333); // any date value, last 4 params can be anything
var d2 = new Date(2013, 9, 3, 11, 42, 32, 533);
d1.setHours(0); d1.setMinutes(0); d1.setSeconds(0); d1.setMilliseconds(0);
d2.setHours(0); d2.setMinutes(0); d2.setSeconds(0); d2.setMilliseconds(0);
daysLeft = (d2.getTime() - d1.getTime())/(24*60*60*1000);
alert('Dear customer, there is(are) ' + daysLeft + ' day(s) left on your order!' );
}
</script>
Show Remaining Days on Order
EDIT: adding PHP version
<?php
$d1 = New DateTime('2013-08-28 06:25:00');
$d2 = new DateTime(); // now
$drip = 55;
$interval = $d2->diff($d1); // time difference
$days_left = $drip - $interval->format('%a'); // in days, subtract from drip
echo "There are $days_left days left\n";
?>
I hope I don't get marked down for not suggesting a specific answer, but time and date calculations are very tedious and JavaScript's Date() provides limited options. So rather than offer some ugly code, I suggest you take a look at moment.js at momentjs.com. Once you attach the script to your pages, you can easily manage all kind of date formats, and set up a function that will allow you to do math on dates and automatically generate your date ranges - it will even let you format them in to user friendly formats like "in 3 days", which I think is what you want. If your app has anything to do with time, and most do, I can't recommend Moment highly enough.