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.
Related
<cfscript>
SetTimeZone("Asia/Karachi"); //same as our windows server timezone
</cfscript>
<cfoutput>
<cfset mydate = 'June 01, 2008'>
<cfset JobStartDate=CreateODBCDateTime(mydate)>
#JobStartDate#
</cfoutput>
Error: Date value passed to date function createDateTime is unspecified or invalid. Specify a valid date in createDateTime function.
I am using ColdFusion 2021 (update 4) on windows server. Under JVM details Java Default Locale is en_US.
Error can reproduced on: cffiddle.org
Would work just fine with other dates for e.g. July 01, 2008 (okay), May 15, 2009 (okay) etc. But shows error with June 01, 2008 (error) and April 07, 2002 (error). Not sure if there might be other dates.
Additional note: Can this issue be associated with the daylight saving in Pakistan?
Daylight Saving Revival
In 2008 Pakistan used daylight saving time for the first time since 2002 to address its energy crisis. The clocks moved one hour ahead (to UTC+6) at midnight between May 31 and June 1 in 2008. The need for daylight saving time during the peak summer season in Pakistan came in light of the country’s struggle for an approximate 4000-megawatt power shortfall. (reference)[https://www.timeanddate.com/news/time/pakistan-extends-dst-2008.html]
Any help would be greatly appreciated. Thanks
I'm afraid the (originally ~) accepted answer to this isn't correct. The problem is entirely down to the daylight savings issue the original poster mentioned.
The original code is this:
<cfset mydate = 'June 01, 2008'>
<cfset JobStartDate=CreateODBCDateTime(mydate)>
As mentioned, CreateODBCDateTime expects a date/time object, not a string, so the first thing CF needs to do is to convert 'June 01, 2008' to date/time, so the equivalent of this:
<cfset mydate = createDateTime(2008,6,1,0,0,0)>
I've added the hour, minute and seconds part there because they are necessary to create a date/time object. You've given it no time part, so CF has to assume zeros there.
And guess what? on June 1 2008 under the daylight savings rules in Pakistan, there is no such thing as 00:00:00. At the stroke of midnight, time shunted forward to 01:00:00. Hence the error:
Date value passed to date function createDateTime is unspecified or invalid
It's telling you exactly what the problem is. One will always get this when trying to use a time that doesn't exist due to daylight savings vagaries. It's exactly the same situation as if one tried to specify the date part as "Feb 32" or something more obviously invalid.
One will get the same error on 2009-04-15 for the same reason: that's when daylight saving started that year.
This demonstrates why servers should always be set to UTC. There are very seldom "unexpected" gaps in the time (the odd corrective leap-second notwithstanding), so these problems simply don't arise. If you use UTC and then adjust the timezone for display for humans when necessary, CF will always get it right.
Another point. Saying that code worked fine in older versions of CF is incorrect (this came up in comments to the earlier answer). SetTimeZone was only added to CFML on ColdFusion for CF2021, and the code in the question errors on earlier versions. So whatever you were or were not experiencing / testing with on older versions of CF was not this issue.
Can this issue be associated with the daylight saving in Pakistan?
No, this issue isn't associated with the daylight saving in Pakistan.
Update: As Adam Camaron correctly mentioned...
The problem is entirely down to the daylight savings issue the original poster mentioned.
My initial findings turned out to be incorrect. Please read Adam Camerons very interesting answer to this issue for further deep explanation. His answer should be the accepted one.
I'll keep my answer post active for further reference, because it might be helpfull giving a better overview about similar issues dealing with dateTime objects in CFML.
===========================
Orignal answer:
According to the cfml documentation about CreateODBCDateTime() you need to pass a dateTime-Object as an argument to CreateODBCDateTime(). Your variable mydate = 'June 01, 2008' is just a string that represents a date, but it's not a dateTimeobject.
July 01, 2008 (okay), May 15, 2009 (okay) etc. But shows error with June 01, 2008 (error) and April 07, 2002 (error)
The cfml engine will try somehow to deal with the submitted string and cast it to the correct data type, but this may or may not work: It's simply isn't offically supported, so I'd rather not do it that way.
To create a dateTimeObject you need to parse that string to a dateObject first, e.g. using lsParseDateTime(), and like #sos correctly commented, if you are using different locales, better to always pass the correct locale that the string content represents as an attribute:
<cfoutput>
<cfset mydate = 'June 01, 2008'>
<cfset JobStartDate=CreateODBCDateTime( lsParseDateTime( mydate, "en_US" ))>
#JobStartDate#
</cfoutput>
If your dateTime data is suitable, an alternative would be creating a dateTimeObject from scratch by using createDateTime() function first, e.g.:
<cfoutput>
<cfset mydate = createDateTime(2008,5,1,0,0,0)>
<cfset JobStartDate=CreateODBCDateTime( mydate )>
#JobStartDate#
</cfoutput>
Regarding timeshifts across the world, it depends how you are getting and saving your time data and to whom in the world you are delivering it to. In worldwide environments I'd usually save dates to UTCs and output it accordingly by using TimeZone functions.
Side note... because this is commonly missunderstood so I'm posting it here just for posterity: "locales" adapts the string to typical readable (traduced) strings, as they are commonly read and identified by the respective cultures, but they don't change timeZones.
To understand that a little more, I can warmly recommend watching this video about timeZones from Lucee. It's not from ColdFusion but it explains a lot about time internationalization and timezones in CFML and some of it pitfalls.
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.
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
Mysql table one row =>
id = 1
time = "21:00" //datatype => TIME
name = "xyz"
while i am fetching the data
#person = #person.all
[#<persons id: 1, time: "2000-01-01 21:00:00, name: "xyz", created_at: "2014-03-19 05:13:43", updated_at: "2014-03-19 05:13:43", creator_id: nil">
#person[0].time # 2000-01-01 21:00:00
It should be "21:00" Right?
Why i am getting "2000-01-01 21:00:00" output any suggestion ??
After fetching data from query, you can format to time for displaying:
fetch all the records:
#person = #person.all
format to time.
#person.first.time.strftime("%H:%M")
for getting more information about date and time formating click here
#person[0].time returns the Ruby Time object for that value, which includes date. If you're outputting it directly to the console or browser window, Ruby is converting it to a default string representation of the Time object which, again, includes the date.
To format the time for display, you'll want to look at your options for date/time formatting using Rails' internationalization API.
try using strftime - it lets you specify format
ie something like:
#person[0].time.strftime("%m/%d/%Y %H:%M:%S")
Changing datatype from TIME TO VARCHAR :
It is not good approach. I think you should consider all the case about time, there is a lot possibility where you required TIME object to other operation like date.
If you store hours and minutes in VARCHAR then you can not perform any operation like TIME object. please think about, if you required hours or date from database in future but you have store only hours and minutes in database, you did not store (TIME Object)it, then it will be considered bad approach and failure.
you store TIME at the place of hours and minutes then It is good cause for future perspective.
If you store time object then you are store additional information with hours and minutes. If you will required Date, time, hours, minutes and even seconds then you can calculate by time formating.
If you store time then there is only one extra effort time formating that is negligible in perspective of performance.
To store TIME Object instead of hours and minutes in string format is always better.
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') }
}