I need to ALWAYS stamp my DB with Pacific Time, regardless if it's August or February.
Pacific Time is, the actual US west coast time at anytime of the year:
During Daylight saving times PT = PDT (Pacific Daylight time) = UTC - 7
During Non Daylight saving times PT = PST (Pacific Standard Time 0 = UTC - 8
I am using C# and do the following:
TimeZoneInfo pacificZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
CreatedDate = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, pacificZone);
Would that automatically take into account Daylight saving times, or do I need to account for this by doing this:
TimeZoneInfo pacificZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
CreatedDate = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, pacificZone);
if (!TimeZoneInfo.Local.IsDaylightSavingTime(CreatedDate))
{
CreatedDate = CreatedDate.AddHours(-1);
}
Is my first or 2nd code snippet the correct one?
The first block is the correct one.
Test code
var utcDateDuringDaylightSavingsTime = new DateTime(2018, 7, 1, 15, 30, 30, DateTimeKind.Utc);
TimeZoneInfo pacificZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
var localDateDuringDaylightSavingsTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateDuringDaylightSavingsTime, pacificZone);
var localDateNotDuringDaylightSavingsTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateDuringDaylightSavingsTime.AddMonths(5), pacificZone);
Console.WriteLine(utcDateDuringDaylightSavingsTime.ToString("o") + "\t\tUTC");
Console.WriteLine(localDateDuringDaylightSavingsTime.ToString("o") + "\t\t Local during daylight saving");
Console.WriteLine(localDateNotDuringDaylightSavingsTime.ToString("o") + "\t\t Local not during daylight saving");
Output
2018-07-01T15:30:30.0000000Z UTC
2018-07-01T08:30:30.0000000 Local during daylight saving
2018-12-01T07:30:30.0000000 Local not during daylight saving
Related
Consider the code below. I have a list of dates around the point in time when CEST changes from summer to winter time. I need to convert them to UTC. However using this code the midnight gets lost, I can't understand how to fix it.
DateTime firstDate = new DateTime(2020, 10, 24, 21, 0, 0);
DateTime lastDate = new DateTime(2020, 10, 25, 3, 0, 0);
DateTime[] dates = Enumerable.Range(0, (lastDate - firstDate).Hours + 1)
.Select(r => firstDate.AddHours(r))
.ToArray();
TimeZoneInfo tzo = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
List<DateTimeOffset> offsets = new List<DateTimeOffset>();
foreach(var date in dates)
{
var timeSpan = tzo.GetUtcOffset(date);
var offset = new DateTimeOffset(date, timeSpan);
offsets.Add(offset);
}
10/24/2020 09:00:00 PM +02:00 = 19:00Z
10/24/2020 10:00:00 PM +02:00 = 20:00Z
10/24/2020 11:00:00 PM +02:00 = 21:00Z
10/25/2020 12:00:00 AM +02:00 = 22:00Z
10/25/2020 01:00:00 AM +02:00 = 23:00Z
10/25/2020 02:00:00 AM +01:00 = 01:00Z - What happened to 00:00Z?
10/25/2020 03:00:00 AM +01:00 = 02:00Z
You're converting from what I'd call a "local date/time" to a UTC value. Some local date/time values are skipped and some are repeated, due to daylight saving transitions (and other time zone changes).
In the situation you're showing, every local time between 2am inclusive and 3am exclusive happened twice, because at 3am (the first time) the clocks went back to 2am - this line:
10/25/2020 02:00:00 AM +01:00 = 01:00Z
... shows the second mapping of 2am. But at 2020-10-25T00:00:00Z the local time was also 2am due to the clocks going back. Your conversion is ambiguous, in other words.
The TimeZoneInfo documentation states:
If dateTime is ambiguous, or if the converted time is ambiguous, this method interprets the ambiguous time as a standard time.
Here, "standard time" is the second occurrence of any ambiguous time (because it's a transition from daylight time to standard time).
Fundamentally, if you only have local values then you have incomplete information. If you want to treat ambiguous values as daylight time instead of standard time (or flag them up as ambiguous), you can always use TimeZoneInfo.IsAmbiguousTime(DateTime) to detect that.
The problem is that there are two 2AM's on 25th October 2020 - 02:00 AM +02:00 and 02:00 AM +01:00.
Since the source DateTime has no offset available, the GetUtcOffset method has no way to determine which 2AM the value refers to, and so it defaults to using the non-DST offset - 02:00 AM +01:00.
Depending on what you're actually trying to do, you may be able to resolve this by converting the start time to UTC, generating a list of UTC DateTimeOffset values, and then converting them back to the desired time-zone:
DateTime firstDate = new DateTime(2020, 10, 24, 21, 0, 0);
TimeZoneInfo tzo = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTimeOffset firstDateUtc = TimeZoneInfo.ConvertTime(firstDate, tzo, TimeZoneInfo.Utc);
DateTimeOffset[] utcDates = Enumerable.Range(0, 7).Select(r => firstDateUtc.AddHours(r)).ToArray();
DateTimeOffset[] offsets = Array.ConvertAll(utcDates, d => TimeZoneInfo.ConvertTime(d, tzo));
Output:
24/10/2020 21:00:00 +02:00
24/10/2020 22:00:00 +02:00
24/10/2020 23:00:00 +02:00
25/10/2020 00:00:00 +02:00
25/10/2020 01:00:00 +02:00
25/10/2020 02:00:00 +02:00
25/10/2020 02:00:00 +01:00
Alternatively, you might want to look at NodaTime, which provides a much clearer model for working with dates and times.
I need to create a DateTime with a set date and time which will be in a specific time zone(West Asia Standard Time, W. Europe Standard Time etc).
DST must be preserved, so offset is out because for half of the year for a given time zone it will be for example +2h and for the other half +3h.
Then I want to convert the date to UTC.
I tried to do it in such a way that I could add this timezone offset later. However, firstly I do not like this solution and I am afraid that I will lose one hour when the time changes twice a year, and secondly I get an error:
"The UTC Offset for Utc DateTime instances must be 0."
var testTime = new DateTime(testDate.Year, testDate.Month, testDate.Day, 4, 0, 0, DateTimeKind.Utc);
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("West Asia Standard Time");
var timezoneTime = TimeZoneInfo.ConvertTimeFromUtc(runTime, timeZoneInfo);
var offset = timeZoneInfo.GetUtcOffset(timezoneTime);
I would like to get this kind of code
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("West Asia Standard Time");
var testTime = new DateTime(testDate.Year, testDate.Month, testDate.Day, 4, 0, 0, timeZoneInfo);
var utcTime = testTime.ToUniversalTime();
So, to sum up, I want to have method, where I pass year, month, day, hour, minute and timeZone and in return I will get DateTime that is in UTC
In javascript there are libraries, where the given time zone is given as a parameter but I have to do it on the server side.
You'd basically need TimeZoneInfo.ConvertTimeToUtc method.
Just make sure the Kind property of the passed DateTime is Unspecified, otherwise the method has special expectations for the sourceTimeZone argument and will throw exception.
e.g.
var testTime = new DateTime(testDate.Year, testDate.Month, testDate.Day, 4, 0, 0);
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("West Asia Standard Time");
var utcTime = TimeZoneInfo.ConvertTimeToUtc(testTime, timeZoneInfo);;
During a Daylight Saving Time transition, the clock is moved forward, and so a specific hour will not exist in that specific day for that specific time zone.
Is there an easy way in .NET to find out if an hour exists or not for a time zone?
The only way I found was by trying to convert an hour to UTC, and check for an exception:
public bool IsValidTime(DateTime date, TimeZoneInfo tzi)
{
try
{
date = DateTime.SpecifyKind(date, DateTimeKind.Unspecified);
TimeZoneInfo.ConvertTimeToUtc(date, tzi);
return true;
}
catch
{
return false;
}
}
And so running something like this will return false:
var date = new DateTime(2020, 3, 8);
var tzi = TimeZoneInfo.FindSystemTimeZoneById("Cuba Standard Time");
var isValid = IsValidTime(date, tzi);
Is there any built in way of doing this, that is less messy?
You can use IsInvalidTime method of TimeZoneInfo.
From Microsoft : https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo.isinvalidtime?view=netframework-4.6.2
Example: In the Pacific Time zone, daylight saving time begins at 2:00 A.M. on April 2, 2006. The following code passes the time at one-minute intervals from 1:59 A.M. on April 2, 2006, to 3:01 A.M. on April 2, 2006, to the IsInvalidTime method of a TimeZoneInfo object that represents the Pacific Time zone. The console output indicates that all times from 2:00 A.M. on April 2, 2006, to 2:59 A.M. on April 2, 2006, are invalid.
// Specify DateTimeKind in Date constructor
DateTime baseTime = new DateTime(2007, 3, 11, 1, 59, 0, DateTimeKind.Unspecified);
DateTime newTime;
// Get Pacific Standard Time zone
TimeZoneInfo pstZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
// List possible invalid times for a 63-minute interval, from 1:59 AM to 3:01 AM
for (int ctr = 0; ctr < 63; ctr++)
{
// Because of assignment, newTime.Kind is also DateTimeKind.Unspecified
newTime = baseTime.AddMinutes(ctr);
Console.WriteLine("{0} is invalid: {1}", newTime, pstZone.IsInvalidTime(newTime));
}
I have a variable with date time which I have to set on a specific date by these rukles and scenarios:
The API that I connect to has a daily limit and once that limit is reached I have to wait until NEXT DAY until 9:10 AM CEST <= This is very important
So I've been simply doing this:
var localTime = TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time"));
var tomorrowAt0910 = localTime.AddDays(1).Date + new TimeSpan(9, 10, 0);
And I have realized that this code has a bug, because I can have following scenarios:
Let's say my application would expire on 30th of July at 15:00 PM in which case this logic up there would be VALID
BUT
We have a next following scenario which is more likely to happen:
Application expires on 31st of July 5:00 AM, in which case this logic is faulty because RENEWAL DATE will be set to 1st of August 9:10AM WHICH IS BAD
If the application expires in this second case, I should set the date to same day and few hours difference (from 5AM to 9AM)
How could I do this?
It sounds like what you really want is to say:
Find the current time in Central Europe
Find 9:10am on the same date
If 9:10am is after the current time, add a day
So something like:
// No need to do this more than once
private static readonly TimeZoneInfo centralEuropeZone =
TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time")
private static DateTime GetUtcResetTime()
{
// Using UtcNow to make it clear that the system time zone is irrelevant
var centralEuropeNow = TimeZoneInfo.ConvertTime(DateTime.UtcNow, centralEuropeZone);
var centralEuropeResetTime = centralEuropeNow.Date + new TimeSpan(9, 10, 0);
if (centralEuropeResetTime <= centralEuropeNow)
{
centralEuropeResetTime = centralEuropeResetTime.AddDays(1);
}
return TimeZoneInfo.ConvertTimeToUtc(centralEuropeResetTime, centralEuropeZone);
}
I've made that return a UTC DateTime so that no other code needs to worry about which zone it's in.
Check if the expire date is less that the current date, if so add one day.
DateTime expireDate = new DateTime(2018, 7, 30, 22, 0, 0); //for testing
DateTime tomorrowAt0910 = DateTime.Now.Date.AddHours(9).AddMinutes(10);
if (expireDate.Date < DateTime.Now.Date)
{
tomorrowAt0910.AddDays(1);
}
I have written a code which basically pulls out transactions from my DB in a PST time zone. What I'd like to do then is simply convert those dates into CEST time zone and IST (Israel Standard Time).
I did something like following :
var transactions = ctx.UserStores.Where(x => x.UserId == loggedUser.UserId).SelectMany(x => x.StoreItems.SelectMany(y => y.StoreItemTransactions)).ToList();
var hourlyData = transactions
.GroupBy(x => TimeZoneInfo.ConvertTime(x.TransactionDate.Value, TimeZoneInfo.FindSystemTimeZoneById(timeZone)).Hour)
.Select(pr => new HourlyGraph { Hour = pr.Key, Sales = pr.Sum(x => x.QuantitySoldTransaction) })
.ToList();
where timeZone parameter can be one of following:
Central European Standard Time
Israel Standard Time
Pacific Standard Time
Naurally when timeZone parameter is = PST I would expect the same results in my list... But the weird thing is the results get completely shuffled up and I'm not sure why ...
So the dates in my DB are kept in PST time zone and I'm trying to convert them into one of these 3 above time zones...
What am I doing wrong here??
Sample code that uses the version of TimeZoneInfo.ConvertTime which expects both a source and target timezone.
DateTime sourceTime = new DateTime(2015, 6, 10, 10, 20, 30, DateTimeKind.Unspecified);
TimeZoneInfo sourceTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
foreach(var targetTimeZoneID in new string[] { "Pacific Standard Time", "Israel Standard Time", "Central European Standard Time" })
{
TimeZoneInfo targetTimeZone = TimeZoneInfo.FindSystemTimeZoneById(targetTimeZoneID);
var converted = TimeZoneInfo.ConvertTime(sourceTime, sourceTimeZone, targetTimeZone);
Console.WriteLine("{0}: {1:yyyy-MM-dd HH:mm:ss}", targetTimeZoneID, converted);
}
Console.ReadLine();
Output is:
Pacific Standard Time: 2015-06-10 10:20:30 Israel Standard Time:
2015-06-10 20:20:30 Central European Standard Time: 2015-06-10
19:20:30