Web Service Dates with timezone info - web-services

I am quering a (.net) web service from Excel (takes cover from the backlash), which returns a array of dates. I have noticed that any date that is on the day boundry gets shifted forward 1 hour, I have checked the web service on the server and the original date is correct.
I then used Fiddler to view the call on the client machine, and the dates which are at midnight have a Z on the end (to mark it as UTC) where as all other date times don't.
UPDATE The above statement is wrong, it is the first and last date that is marked with a Z, it doesn't matter what the time is. The rest is correct that the client only adjusts the first and last date
I take it SOAP is then changing this from UTC to local (BST) and therefore adding an hour.
My question is how can I stop the Z from being added onto these dates (or change it to local)?
I have checked the culture in IIS 7.5 and it is set to en-GB, the server is set to UK.

It's a little fiddly, and this isn't really an answer but should give you some things to try.
One way might be to remove the offset. I don't have the code to had but in psudeo-like code it might be
TimeZone tz = GlobalizationNamespace.GetTimeZone("Greenwich Mean Time");
SomeDateTimeNoOffset = SomeDateTime.AddHours(tz.GetUtcOffset(SomeDateTime));
This should might stop the service from putting a Z at the end as it has no TimeZone offset.
Another other option would be to expose the property in the Service Contract as a String
public string DateTimeNoTzInfo
{
get { DateTime.ToString('yyyy-MM-ddThh:mm:ss.ttttt') }
}

Related

Django use UTC offsets for current timezone

Django attempts to address the timezone problem by storing dates internally in UTC and converting them to the client's timezone for display. This sounds fine and good in theory, until you realize two major things:
Many timezones can and do exist inside of the same UTC offset.
Since there are no timezone HTTP headers, we need to determine the timezone of the client manually, and this requires the use of JavaScript. However, JavaScript can only reliably determine the UTC offset of the client and may not guess the correct timezone.
With these two problems in mind, I assume a simple solution would be to ignore timezones, DST, etc. altogether and rely instead on the client's current UTC offset. On each page load, JavaScript on the client would update the client's cookie with the client's current UTC offset and middleware in Django would load that value for each request.
Here is the problem: Django makes use of get_current_timezone() which retrieves it's data from the value set when timezone.activate() was last called. timezone.activate() takes a timezone object as an argument.
Is there a way to use timezone.activate() with only a UTC offset?
The solution you describe, of getting the client's current UTC offset and sending back to the server, either via a cookie, or some other mechanism, is a common approach. Unfortunately it's flawed. Just because people do this doesn't make it a good idea.
The problem is that the offset you gather from the client is for a specific moment in time. However, you may not be working with that same moment in time on the server.
For example, you might call new Date().getTimezoneOffset() on the client, which gives you a value of 480, which is 480 minutes West of UTC, or UTC-08:00 (note the sign inversion). So you pass 480 to the server, load a date from the DB in UTC, and apply the offset. Except, perhaps the date you loaded was from several months ago, and the client's offset for that date was UTC-07:00. You have therefore applied the wrong offset, and produced a resulting value that is an hour off from what it should be.
A time zone cannot be identified by an offset alone. A time zone identifier looks like "America/Los_Angeles", not just UTC-8. This is a very common mistake. Read more under "time zone != offset" in the timezone tag wiki.
There are only two correct ways to handle this scenario:
Use a library like jsTimeZoneDetect or moment-timezone to guess the time zone of the browser, then let the user pick their time zone, defaulting to the guessed value. You can then use the selected or guessed time zone in your server-side code with Django or whatever.
Send only UTC to the client, do the conversion from UTC to local time in the browser using JavaScript. (The browser understands the behavior of the local time zone where it is running, even if it has trouble identifying it.) The catch here is - older browsers might possible convert older dates incorrectly, due to this bug. But for the most part, this is still a reasonable approach.

timezones and doing analytics on tables

This strange behavior has recently came to my attention, while I was testing my Rails app on local environment in which I use around_filter to set the timezone to registered user (the default timezone is UTC).
What I did was that I registered a new user in my app. My current time was 10pm GMT-5 (March 3), and this user's created_at time was saved to database to 4am UTC (March 4). Now, I know that this time is saved in database with the timezone settings, but here comes the problem:
I use a graph for visual representation of daily registered users, and when I called the following function to tell me number of users registered in the last few days:
from ||= Date.today - 1.month
to ||= Date.today
where(created_at: from..to).group('DATE(created_at)').count
It would say that this user was registered in March 4, while it was in fact registered on March 3 from my perspective.
My question is:
How should I call where function and group by a created_at column, so that the dates with be affected correctly (according to my timezone) ?
Or is there something else that I should be doing differently?
I'm not a rubyist, so I'll let someone else give the specific code, but I can answer from a general algorithmic perspective.
If you're storing UTC in the database, then you need to query by UTC as well.
In determining the range of the query (the from and to), you'll need to know the start and stop times for "today" in your local time zone, and convert those each to UTC.
For example, I'm in the US Pacific time zone, and today is March 7th, 2015.
from: 2015-03-07T00:00:00-08:00 = 2015-03-07T08:00:00Z
to: 2015-03-08T00:00:00-08:00 = 2015-03-08T08:00:00Z
If you want to subtract a month like you showed in the example, do it before you convert to UTC. And watch out for daylight saving time. There's no guarantee the offsets will be the same.
Also, you'll want to use a half-open interval range that excludes the upper bound. I believe in Ruby that this is done with three dots (...) instead of two (at least according to this).
Grouping is usually a bit more difficult. I assume this is a query against a database, right? Well, if the db you're querying has time zone support, then you could use it convert the date to your time zone before grouping. Something like this (pseudocode):
groupby(DATE(CONVERT_TZ(created_at,'UTC','America/Los_Angeles')))
Since you didn't state what DB you're using, I can't be more specific. CONVERT_TZ is available on MySQL, and I believe Oracle and Postgres both have time zone support as well.
Date.today will default to your system's set timezone (which by the way should always be UTC, here's why) so if you want to use UTC, simply do Time.zone.now.to_date if rails is set to UTC
Otherwise you should do
Time.use_zone('UTC') do
Time.zone.now.to_date
end
After this you should display the created_at dates by doing object.created_at.in_time_zone('EST')
to show it in your current timezone

Web server subtracting 1 hour from dataset datetime for some days

We have a web server running Windows 2003 Standard and the time zone is set to GMT-06:00 Central Time, and the box is checked to adjust for daylight saving changes.
A web service on this server queries a datetime field and when the datetime is fetched it is correct. When the dataset is returned to the client 1 hour is subtracted from the datetime if the date is Mar 9-31, Apr 1-5, Oct 26-31, or Nov 1-5. These are the dates that the DST time change can happen on.
It does not matter when the data was saved to the database. If I save a date of 4/1/2013 today, it will be returned to the client minus the 1 hour.
We have verified that SQL is storing the date correctly since it is being returned to the web service correctly.
If I convert the date to a date string at the web server before returning it to the client, the correct date string is returned.
All dates outside of the possible DST dates are good.
All dates during DST that are not on a possible change date are good.
As an example, a date saved as 4/1/2013 12:00:00 AM will be returned as 3/31/2013 11:00:00 PM.
A date saved as 4/6/2013 12:00:00 AM will be returned as 4/6/2013 12:00:00 AM.
I added a web method to the web server to return a date value of Now() and it returns the correct date.
The only thing I have found that is similar was something about a XML rule that says all datetime values are to be transmitted using an offset. I'm not 100% sure but I don't think this is it because only some dates are changed.
Any thoughts/suggestions of what else to look at to get this resolved?
Edit: I have found some dates on the dates listed above that are correct.
I'm going to take a shot at expanding this question, since i've had a similar issue in serialization of data objects.
Take a System.DateTime object that you want to write into a DataColumn. The DateTime object will by default return the DateTime.Kind property as [Unspecified]. When the DataColumn is then set to this DateTime object the DataColumn has a DateTimeMode property that resets to [UnspecifiedLocal].
There is not offest during serialization of DataColumn when the DateTimeMode is [Unspecified] or [UTC]. But when the DateTimeMode is set to [UnspecifiedLocal] or [Local], the offeset is applied. This is where the time can go up or down depending on the timezone or daylight savings configuration.
Sad news is that I can share your problem, but don't have a decent solution. Hope this helps your search.
I can only think of some ugly solutions, but i have not tested any. If i find an elegant solution i will try post again.

How do I force boost::posix_time to recognize timezones?

I'm reading timestamp fields from a PostgreSQL database. The timestamp column is defined as:
my_timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW()
When reading from the database, I convert it to a boost timestamp like this:
boost::posix_time::ptime pt( boost::posix_time::time_from_string( str ) );
The problem seems to be that boost::posix_time::time_from_string() ignores the timezone.
For example:
database text string == "2013-05-30 00:27:04.8299-07" // note -07 timezone
boost::posix_time::to_iso_extended_string(pt) == "2013-05-30T00:27:04.829900"
When I do arithmetic with the resulting ptime object, the time is off by exactly 7 hours. Is there something better I should be doing to not lose the timezone information?
I think you should be using boost::local_date_time, which handles time zones. There is an example in the documentation that is very similar to what you're trying to do: http://www.boost.org/doc/libs/1_41_0/doc/html/date_time/examples.html#date_time.examples.seconds_since_epoch
EDIT: Boost supports date parsing with specific formats. http://www.boost.org/doc/libs/1_40_0/doc/html/date_time/date_time_io.html#date_time.format_flags
string inp("2013-05-30 00:27:04.8299-07");
string format("%Y-%m-%d %H:%M:%S%F%Q");
date d;
d = parser.parse_date(inp,
format,
svp);
// d == 2013-05-30 00:27:04.8299-07
I originally asked this question so many years ago, I don't even remember doing it. But since then, all my database date/time code on the client side has been greatly simplified. The trick is to tell PostgreSQL the local time zone when the DB connection is first established, and let the server automatically add or remove the necessary hours/minutes when it sends back timestamps. This way, timestamps are always in local time.
You do that with a 1-time call similar to this one:
SET SESSION TIME ZONE 'Europe/Berlin';
You can also use one of the many timezone abbreviations. For example, these two lines are equivalent:
SET SESSION TIME ZONE 'Asia/Hong_Kong';
SET SESSION TIME ZONE 'HKT';
The full list of timezones can be obtained with this:
SELECT * FROM pg_timezone_names ORDER BY name;
Note: there are over 1000 timezone names to pick from!
I have more details on PostgreSQL and timezones available on this post: https://www.ccoderun.ca/programming/2017-09-14_PostgreSQL_timestamps/index.html

Convert datetime from one timezone to another (native C++)

Customers from around the world can send certain 'requests' to my server application. All these customers are located in many different time zones.
For every request, I need to map the request to an internal C++ class instance. Every class instance has some information about its 'location', which is also indicated by a time zone.
Every customer can send requests relating to instances belonging to different time zones. To prevent my customers from converting everything themselves to the time zone of the 'target' instance, I have to convert everything myself from one time zone to another. However, I only find in C++ (unmanaged, native) functions to convert times between local time and GTM, but not from/to a time zone that is not your current time zone.
I could ask my customers to send every date time in UTC or GTM, but that does not solve my problem as I still have to convert this to the time zone of the 'instance', which can be any time zone in the world.
I also don't seem to find a Windows function that does this. What I do find is a managed .Net class that does this, but I want to keep my application strictly unmanaged.
Are there any Windows (XP, Vista, 7, 2003, 2008) functions that I can use (and which I overlooked in the documentation), or are there any other free algorithms that can convert between one time zone and the other?
Notice that it is not the GMT-difference that is posing the problem, but the actual DST-transition moment that seems to depend on the time zone. E.g:
Western Europe goes from non-DST to DST the last Sunday before April 1st.
USA goes from non-DST to DST the 2nd Sunday after March 1st.
China has no DST.
Australia goes from non-DST to DST the 1st Sunday after October 1st.
All this DST-transition information is available somewhere in the Windows registry. Problem is: which Windows function can I use to exploit this information.
I don't know of a way to extract information about other TimeZones via the API: I've seen it done by querying the registry though (we do this in a WindowsCE-based product).
The TimeZones are defined as registry keys under
HKLM\Software\Microsoft\Windows NT\Current Version\Time Zones
Each key contains several values, and the one which tells you about offsets & Daylight Savings is the TZI key. This is a binary blob, and it represents this structure:
typedef struct
{
LONG m_nBias;
LONG m_nStandardBias;
LONG m_nDaylightBias;
SYSTEMTIME m_stcStandardDate;
SYSTEMTIME m_stcDaylightDate;
} TZI;
Look up MSDN's TIME_ZONE_INFORMATION page (http://msdn.microsoft.com/en-us/library/ms725481(v=VS.85).aspx) for how to interpret the Bias fields, and especially the StandardDate and DaylightDate fields -- they are gently abused to support constructs like "the last Saturday in April".
HTH