I'm experimenting with PostgreSQL TIME datatype and I notice a strange behavior.
test=# SELECT CURRENT_TIME;
current_time
--------------------
08:43:35.446737+00
(1 row)
test=# SELECT CURRENT_TIME AT TIME ZONE '+04';
timezone
--------------------
04:43:50.475164-04
(1 row)
test=# SELECT CURRENT_TIME AT TIME ZONE '-04';
timezone
--------------------
12:43:54.810124+04
(1 row)
As you can notice, the default timezone is 00, so when I convert it +04, I expect to get the result that I get when converting it with -04
Is anyone familiar with the reasons behind this behavior or this is a bug
You are using POSIX style time zone names, which work a bit strangely. From the docs:
Another issue to keep in mind is that in POSIX time zone names, positive offsets are used for locations west of Greenwich. Everywhere else, PostgreSQL follows the ISO-8601 convention that positive timezone offsets are east of Greenwich.
Also, from the same docs:
We do not recommend using the type time with time zone (though it is supported by PostgreSQL for legacy applications and for compliance with the SQL standard).
Related
I am using IDAA for DB2. At one point I use TO_DATE to convert some dates and it works:
TO_DATE('09/03/2018 06:49:23','MM/DD/YYYY HH:MI:SS')
But when I have a VARCHAR value with milliseconds in the timestamp, TO_DATE returns an error. I looked around online and found an answer that says to use TO_TIMESTAMP but that doesn't work:
TO_TIMESTAMP('09/03/2018 06:49:23.443000','MM/DD/YYYY HH:MI:SS.NNNNNN')
I've looked at every answer on here and tried many variations. I've tried every combination of the functions TO_TIMESTAMP, TO_DATE, TIMESTAMP_FORMAT and the format for milliseconds as FF, FF6, NNNNNN. I get these errors:
NO AUTHORIZED FUNCTION NAMED TO_TIMESTAMP HAVING COMPATIBLE ARGUMENTS WAS FOUND. SQLCODE=-440
SQL error: SQLCODE = -904, SQLSTATE = 57011, SQLERRMC = Invalid Date.. SQLCODE=-904
Maybe it's different for the IDAA? I don't know.
I'm running DB2 for z/OS V11 using IBM Data Studio 4.1.3.
TIMESTAMP_FORMAT for Db2 for z/OS is documented here
https://www.ibm.com/support/knowledgecenter/en/SSEPEK_12.0.0/sqlref/src/tpc/db2z_bif_timestampformat.html
Do note that HH is the same as HH12, not HH24, so it might be that you need, e.g.
$ db2 "values TIMESTAMP_FORMAT('09/03/2018 16:49:23','MM/DD/YYYY HH24:MI:SS')"
1
--------------------------
2018-09-03-16.49.23.000000
1 record(s) selected.
( The above is from Db2 LUW, but I would assume that function works the same on Db2 for z/OS/ and DAA )
Based on the following link -
https://www.ibm.com/support/knowledgecenter/en/SS4LQ8_4.1.0/com.ibm.datatools.aqt.doc/gui/concepts/c_idaa_inconsistencies.html
IBM Db2 Analytics Accelerator for z/OS does not support all date and time formats that Db2 supports. This might lead to different results for accelerated and inhouse Db2 queries if the VARCHAR_FORMAT or TIMESTAMP_FORMAT scalar function is used. The following formats are not supported by IBM Db2 Analytics Accelerator for z/OS:
FF[n] - fractional seconds (000000-999999)
The optional number n is used to specify the number of digits to include in the return value. Valid values for n are the integers from 1-6. The default is 6.
ID - ISO day of the week (1-7)
The value 1 represents Monday. The value 7 represents Sunday.
IYYY - ISO year (0000-9999)
The last four digits of the year based on the ISO week that is returned.
NNNNNN - microseconds (000000-999999)
This format is equivalent to FF6.
RR - last two digits of the year (00-99)
SSSSS - seconds since the previous midnight
We are using JavaMail API to send calendar entries. But the recipients of Outlook have time zone issues, as meetings show wrong timings. In general our approach is as follows:
First of all we have,
SimpleDateFormat iCalendarDateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
we then use iCalendarDateFormat.setTimeZone(TimeZone.getTimeZone(receiverTimeZone));
Finally, we use Calendar.getInstance() for start and end to manipulate Calendar fields,
and hence we have Date startDate = startTime.getTime();
Date endDate = endTime.getTime();
When we are about to send request as per icalendar specification we have ,
"DTSTAMP:" + iCalendarDateFormat.format(startDate) + "\n" +
"DTSTART:" + iCalendarDateFormat.format(startDate)+ "\n" "DTEND:" + iCalendarDateFormat.format(endDate)+ "\n"
Is this the correct approach?. Please comment.
Thanks
tl;dr
iCalendar format tracks the date-time separately from its intended time zone. You must juggle both parts appropriately.
Always use java.time classes. Never use legacy classes like Calendar & SimpleDateFormat.
Details
Caveat: I have not used iCalendar data before. So I may be incorrect in my understanding.
Looking at pages 31-33 of the RFC 5545 spec, it seems the authors of that spec assume you always want the date-time to be recorded separately from the time zone.
A moment, a point on the timeline, needs the context of a time zone or offset-from-UTC. For example, "noon on the 23rd of January next year, 2021" is not a moment. We do not know if you mean noon in Tokyo Japan, noon in Toulouse France, or noon in Toledo Ohio US — all very different moments, several hours apart.
To provide the context of an offset, a date and time must be accompanied by a number of hours-minutes-seconds such as 08:00. For an offset of zero hours-minutes-seconds, use +00:00.
2021-01-23T12:00:00+00:00
As an abbreviation of an offset of zero, +00:00, the letter Z can be used, pronounced “Zulu”. For example:
2021-01-23T12:00:00Z
But, strangely, the iCalendar spec wants to track the date and the time-of-day separate from the time zone. So this:
2021-01-23T12:00:00
…and a time zone field elsewhere:
America/New_York
And the iCalendar spec opts for the harder-to-read “basic” variation allowed by ISO 8601, which minimizes the use of delimiters. So this:
20210123T120000
For such a string, we must parse as a LocalDateTime. This class represents a date with a time-of-day but lacking any time zone or offset-from-UTC.
DateTimeFormatter f = dateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmss" ) ;
String input = "20210123T120000" ; // “Basic” variation of ISO 8601 format.
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
To determine a moment, we must apply a time zone. I assume iCalendar uses proper time zone names (Continent/Region format) and not the 2-4 letter pseudo-zones such as PST, CST, IST, and so on.
String zoneName = receiverTimeZone ; // Variable name taken from your code example, though you neglected to show its origins.
ZoneId z = ZoneId.of( zoneName ) ;
Apply the zone to get a ZonedDateTime, a moment, a point on the timeline.
ZonedDateTime zdt = ldt.atZone( z ) ;
Going the other direction, let's start with the current moment.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;
And generate string values for iCalendar.
DateTimeFormatter f = dateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmss" ) ;
String iCal_DateTime = now.format( f ) ;
String iCal_ZoneName = now.getZone().toString() ;
Never use the terrible legacy date-time classes bundled with the earliest versions of Java: Calendar, GregorianCalendar, java.util.Date, SimpleDateFormat, and so on. These were supplanted years ago by the modern java.time classes defined in JSR 310.
Hard to tell without seeing the actual content of your iCalendar file, along with the expected start and end datetime with timezone information but you seem to be generating the DTSTART in floating time (datetime with local time). Although your code sample seems to imply that you have access to the recipient's timezone (receiverTimezone), this is a very fragile approach.
Instead, you should use either the datetime with UTC time or the datetime with local time and timezone (where the timezone does not have to be the receiver timezone).
If the event is not recurring, the most simple approach is to use datetime with UTC time.
See https://www.rfc-editor.org/rfc/rfc5545#section-3.3.5 for the definition of each format.
I had same problem, for which I struggle lot. So below are my findings:
Outlook works smoothly with UTC Timezone. If we set date & time with UTC Timezone then outlook automatically converts this UTC Time into user corresponding Timezone. We will have to use 'Instant' object for DTSTART:, DTEND: and for DTSTAMP(Optional but recommended) also.
Quick Test just use "DTSTART:"+Instant.now() in ical String.
And in Java 8 for getting UTC Time java time API provides Instant.now() through which you can get your system time in UTC format. Java 8 also provides method like
a. Instant.ofEpochMilli() - This returns Instant which can directly use in ical Sting.
b. new Date().toInstant() Which returns UTC Instant object.
There are few scenarios where input date and time sources are different:
If you are fetching Date and Time from database then in this case database is not storing Timezone its only saving Date & Time. So first convert the Date & Time in that Timezone in which it was saved in database, in my case I was storing Date & Time after converting in 'EST' Timezone and Date value was of EST but time zone was not there in DB. So while fetching Date & Time value from DB I have appended Timezone in the Date value and then further converted to EPOC time using below method
public static long getEpocTimeWithTimezone(Date date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DateTimeFormatter dateTimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse(simpleDateFormat.format(date), dateTimePattern);
long epochInMilliSeconds = dateTime.atZone(ZoneId.of("America/New_York")).toEpochSecond() * 1000;
return epochInMilliSeconds;
}
Then Just Use as below code for ical String:
Instant startDt = Instant.ofEpochMilli(getEpocTimeWithTimezone(//pass your date here
)).truncatedTo(ChronoUnit.MINUTES);
Now set this Instant object(startDt) directly to "DTSTART:":
"DTSTART:"+startDt+"....then in same fashion "DTEND:" also.
In second scenario you have Date with Timezone (make sure after conversion you did not loses your actual Timezone, Like in 1st scenario after saving Date in DB we actually lost Timezone but it was showing Timezone IST that was dummy so be careful about this)
So in this case just assume myDateObject is Date object. So just get the Instant (which
will be in UTC) object from myDateObject by using toInstant() of Date class.
Instant startDt = myDateObject.toInstant().truncatedTo(ChronoUnit.MINUTES);
I am using .truncatedTo(ChronoUnit.MINUTES); because if we will not use this then
we might get some extra min or second in Meeting invite Time section.
So the final String for outlook mail should be some like:
.
.
.
"BEGIN:VEVENT\n"+
"DTSTART:"+startDt+"\n"+
"DTEND:"+endDt+"\n"+
.
.
.
VVI Note: Since Z is representation of UTC time zone, So just adding Z in the last of Time will not be UTC zoned Time, You will have to convert the Date & Time then only accurate time will come on Outlook. For verifying your Time is in UTC format or not just save the .ics attached file (which you got in Email) in local and check Date & Time are coming as DTSTART:2020-05-15T13:57:00Z or not If not then you are not converting the Date correctly in UTC.
I am trying to use the new AT TIME ZONE syntax in SQL Server 2016 and Azure SQL. I'm just trying to get the current time in London as a datetime, adjusted for daylight saving. At the time of running all of the commands below, the time in London was 3.27am.
The first step is to get a datetimeoffset, which I can successfully do as follows:
DECLARE #dto datetimeoffset
SET #dto = (SELECT GETUTCDATE() AT TIME ZONE 'GMT Standard Time')
SELECT #dto
This returns a value as I would expect:
2016-04-04 02:27:54.0200000 +01:00
Next, I want to convert that to a datetime, which is what my applications expect. I've tried three different approaches, none of which give me the result I'm looking for:
SELECT SWITCHOFFSET(#dto,'+00:00')
-- Returns 2016-04-04 01:27:54.0200000 +00:00
SELECT CONVERT(datetime, #dto)
-- Returns 2016-04-04 02:27:54.020
SELECT CONVERT(datetime2, #dto)
-- Returns 2016-04-04 02:27:54.0200000
I feel like I'm missing something obvious - is there an easy way to take a datetimeoffset and return just the date/time part at that offset?
The first line of your code contains the fault:
SELECT GETUTCDATE() AT TIME ZONE 'GMT Standard Time'
GETUTCDATE() returns a datetime, which has no time zone offset information. Thus as described in the MSDN documentation:
If inputdate is provided without offset information, the function applies the offset of the time zone assuming that inputdate value is provided in the target time zone.
So, even though you retrieved the UTC time, you erroneously asserted that the value was in London time (which is UTC+1 for daylight saving time at this date).
The easiest way to handle this is to just fetch the UTC time as a datetimeoffset to begin with.
SELECT SYSDATETIMEOFFSET() AT TIME ZONE 'GMT Standard Time'
This invokes the conversion functionality of AT TIME ZONE, which in the docs states:
If inputdate is provided as a datetimeoffset value, then AT TIME ZONE clause converts it into the target time zone using time zone conversion rules.
Consider that if your data actually comes from a datetime field somewhere, you might need to use both parts of the functionality, like this:
SELECT mydatetimefield AT TIME ZONE 'UTC' AT TIME ZONE 'GMT Standard Time'
The first call to AT TIME ZONE asserts the value is in UTC, giving a datetimeoffset to the second call, which converts it to London time.
The output of any of these is a datetimeoffset, which you can cast or convert to a datetime or datetime2 exactly as you showed in your original question. (Don't use switchoffset for this.)
Also, the Windows time zone identifier for London is always "GMT Standard Time". It is inclusive of both Greenwich Mean Time and British Summer Time, with the appropriate transitions between them. Do not try change it to "GMT Daylight Time" - that identifier doesn't exist. This is also covered in the timezone tag wiki, in the section on Windows time zones.
Since I was unable to find this anywhere else I thought I'd share. You can get the offset in minutes by using datepart (tz) with AT TIME ZONE.
datepart(tz,UTC_Date AT TIME ZONE 'Central Standard Time')
select dateadd(MINUTE,datepart(tz,cast('2018-07-02 17:54:41.537' as datetime) AT Time Zone 'Central Standard Time'),'2018-07-02 17:54:41.537') as CentralTime
returns
CentralTime
2018-07-02 12:54:41.537
I suggest you only store this as a string and qualify that it is a local time representation, otherwise the time SQL Server stores internally would be the wrong actual/physical time, if the server time is correct, but just not in the same time zone. It is why you cannot use convert to represent the same because you are actually changing the datetime value from the real time of occurrence and not just re-representing it i.e. Datetime is always stored as UTC, but entered and displayed in the timezone of the server, so if you enter a local time in a datetime field, the server interprets that time as the time in the server time zone and not the actual time of the event, which results in stored time navigation/deviation if the local time is not the same as the server> Should you then feed the same data to other systems in different time zones, they will have incorrect data and it can get messy. Store the right value in the datetime field and display it as you wish as a string.
I help out a collegue with exporting data from SQL Server 2012. I type manual queries and then copy/paste the results to an Excel sheet that I then share with him. The extract I make will be an excel file that will be manually analysed. No need for automation.
What I try to do is settling for best practice when exporting order statistics grouped by day, trying to learn SQL better. I have a field of type datetime, and I want to convert this to some date format. In my locale, the typical date format is YYYY-MM-DD. I do sometimes share my script with others, that might have another locale. I have found three statements that seem to yield the same values for me.
select top 1
createdat
, CAST(createdat as date) as A
, CONVERT(char(10), createdat,126) as B
, CONVERT(char(10), createdat,127) as C
from dbo.[Order]
resulting in
createdat |A |B |C
2012-12-27 08:23:32.397 |2012-12-27 |2012-12-27 |2012-12-27
From the TSQL MSDN reference (link) I understand that:
A is handled by SQL as type Date, whereas B and C are chars.
B and C should differ by their time zone handling.
But I dont understand:
HOW does B and C handle time zones?
What is the practical difference when copy/pasting to Excel?
Is there practical difference if I share this script with collegues using another locale I should consider?
Should one or the other be preferred?
To answer your questions sequentially:
126 uses the ISO 8601 date standard, which signifies the Year aspect to be the full 4 characters long, rather than just the last two. 127 uses the same date standard, but in Time Zone Zulu, which is a military time zone (4 hours ahead of EST)
There essentially is no difference when copy/pasting to Excel. When opening an Excel doc, the default cell formatting is "General". When you paste any of these date types into Excel, it will register option A as a number (in this case 41270) and based on the pre-existing format from your query will convert it to Date format. Options B and C will first register as text, but since they are in the format of a Date (i.e. they have the "/" marks), Excel can register these as dates as well and change the formatting accordingly.
As long as the person you are sharing your script with uses T-SQL this shouldn't cause problems. MySQL or other variations could start to cause issues.
CAST(createdat as date) is the best option (IMO)
Sources:
SQL Conversion Types
ISO 8601 Details
Zulu Time Zone
I am working in MVC4 project where i am facing problem with time.Actually my project requirement is to show all time used in application according to Brazil time.So i have used GETUTCDATE() for saving time in application.
Now i want to check if DST is on according to time i saved..i mean central time. How do i check this.
I have search on net and found one solution
DECLARE #IsDST BIT;
SET #IsDST = CASE WHEN DateDiff(hour, GetDate(), GetUTCDate()) = 4 THEN 'True'
ELSE 'False' END;
SELECT GETDATE() AS GETDATE,
GETUTCDATE() AS GETUTCDATE,
#IsDST;
But when i try to run this script,it return false ??
But as per DST calculation,it always starts from 2nd Sunday of March and ends on 1st Sunday of November.
Then it should return true ,that DST is on.
Am i doing right or is there another better approach to check if DST is on central time,so that i can show brazil time according to DST
Well, this particular code doesn't work for detecting DST in Brazil, because it just measures the difference right now between local time and UTC, checking for 4 hours difference or not.
Most of Brazil is 3 hours behind UTC in the standard time, and 2 hours behind UTC in the daylight time. So this code probably won't work for you. You can read more in this Wikipedia article.
Daylight Saving Time is very different all over the world, so if you intend to use this approach then you will have to modify your code to match the time zone of the server that it's running on.
Personally, I would recommend not doing this in SQL at all. Time zone conversions aren't really the realm of the database. They work much better in application code. You should work with UTC in your database, and convert it to Brazil or whatever time zone you require in your application.
Since you said this was an ASP.Net MVC4 application, I recommend you either use the .net TimeZoneInfo class, or use the excellent Noda Time library to do your conversions in your .Net code.
Using TimeZoneInfo:
DateTime utcDT = // ... your UTC value returned from the database
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(
"E. South America Standard Time"); // Brazil
DateTime brazilDT = TimeZoneInfo.ConvertTimeFromUtc(utcDT, tz);
Using Noda Time:
DateTime utcDT = // ... your UTC value returned from the database
Instant instant = Instant.FromDateTimeUtc(utcDT);
DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/Sao_Paulo"]; // Brazil
ZonedDateTime brazilZDT = instant.InZone(tz);
DateTime brazilDT = brazilZDT.ToDateTimeUnspecified();