Why is [datetime] converting this UTC time correctly and how can I replicate that with ParseExact - powershell

I feel silly that I cannot figure this one out on my own.
I have dates coming from the CarbonBlack API e.g. 2022-02-15-172040 which are in UTC
The [datetime] type cast works fine if I remove the seconds portion of the string
PS M:\Scripts> [datetime]"2022-02-15-1720"
Tuesday, February 15, 2022 12:20:00 PM
I don't understand how it "knows" that is a UTC string. It is correct of course but I expected 5:20pm for the time portion. I wanted the seconds for the date so I went to parse exact as this doesn't match any format strings as far as I know
PS M:\Scripts> [datetime]::ParseExact("2022-02-15-172040", "yyyy-MM-dd-HHmmss" ,[Globalization.CultureInfo]::CurrentUICulture)
Tuesday, February 15, 2022 5:20:40 PM
Which is the time I expected but the incorrect time.
Why is the [datetime] working when I wouldn't expect it to and what do I need to do to the string or static method call for it to treat that as a UTC string with minimal manipulation?

This is because
([datetime]"2022-02-15-1720").Kind
yields 'Local', while
([datetime]::ParseExact("2022-02-15-172040", "yyyy-MM-dd-HHmmss",[CultureInfo]::InvariantCulture)).Kind
returns 'Unspecified'
If you want the result to handle the string as being Local time and then the result should be in UTC, use:
([datetime]::ParseExact("2022-02-15-172040", "yyyy-MM-dd-HHmmss",[CultureInfo]::InvariantCulture, 'AssumeLocal')).ToUniversalTime()
or
$date = [datetime]::ParseExact("2022-02-15-172040", "yyyy-MM-dd-HHmmss",[CultureInfo]::InvariantCulture)
[datetime]::SpecifyKind($date, 'Local').ToUniversalTime()
Going the other way around, so if you regard the date in the string represents UTC (Universal Time), and you want the result to be in
Local time , you need to do this:
[datetime]::ParseExact("2022-04-29-185121", "yyyy-MM-dd-HHmmss",[CultureInfo]::InvariantCulture, 'AssumeUniversal')
Here, ParseExact() treats the string as UTC and outputs a date converted to Local time
(.Kind --> 'Local'), which is the exact same output as
[datetime]"2022-04-29-1851"
would give: also here, .Kind --> 'Local'`
If then you want the resulting date to be in UTC, you need to convert it back again with .ToUniversalTime()
The tricky part is that using ParseExact() without the third parameter ('AssumeLocal' or 'AssumeUniversal') when parsing a string that has no
indication of it being Local or UTC like the example strings here, is always returning a datetime object with its .Kind property set to Unspecified.
Thanks to mklement0's comment,
in PowerShell (Core) 7+, strings like in the example are no longer recognized and should have a TimeZone indication like '2022-02-15 17:20Z'. ('Z' --> Zulu (UTC) Time)
If you do give it the third parameter, telling it what timezone it should use ('AssumeLocal' or 'AssumeUniversal'), the resulting datetime object will
always have its .Kind property set to Local and the result will be converted to local time in case you have given AssumeUniversal as parameter.

Related

Google Calendar api ignores timezone

Im using the CalendarApi in flutter and in order to get events I use the list method like that:
calendarApi.events.list(
cls.calendarId,
timeZone: <specific timezone>
timeMin: DateTime.now().today().toUtc(),
timeMax: DateTime.now().tomorrow().toUtc(),
),
No matter what timezone I tried it always return the event start and end date in UTC format.
I tried using the timezones in multiple formats:
America/Los_Angeles
UTC - 08:00
GMT format
Pacific Standard Time
None of the following worked.
In addition in the in google calendar's settings the timezone is set correctly.
From the documentation:
Must be an RFC3339 timestamp with mandatory time zone offset, for example, 2011-06-03T10:00:00-07:00, 2011-06-03T10:00:00Z. Milliseconds may be provided but are ignored. If timeMax is set, timeMin must be smaller than timeMax.
Make sure the strings you are sending follow one of these pattens:
YYYY-MM-DDTHH:MM:SS±HH:MM
or
YYYY-MM-DDTHH:MM:SSZ
So for example, the time that this answer was posted would be:
2021-07-27T16:08:02+02:00
or:
2021-07-27T14:08:02Z
Where the Z signifies 'Zulu', or UTC.

Compare String time to Local Server Time

Have a string object with a specific format of date.
Need to check if that dateStr is after the current time on local machine.
Having trouble with conversions and LocalDateTime
String dateStr = "Oct 27 2017 02:29:00 GMT+0000";
public static final String DATE_FORMAT = "MMM dd yyyy HH:mm:ss zzzZ";
I know something is fishy in the below code with the usage of LocalDateTime
public static boolean isFutureDate(String dateStr){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
return(dateTime.isAfter(LocalDateTime.now()));
}
Trouble is with timezones and date conversions.
Please help find the right way of checking if a dateStr is after the current local date this in Java 8?
Local… types have no time zone
You are using the wrong type for your data.
The Local… types including LocalDateTime purposely have no concept of time zone or offset-from UTC. As such they not represent a moment on the time line, only rough idea of a range of possible moments. Use LocalDateTime only when the time zone is unknown or irrelevant; never use it for an actual moment in history.
Use OffsetDateDate for values with an offset-from-UTC, a number of hours and minutes.
Use ZonedDateTime for values with an assigned time zone. A time zone such as Asia/Kolkata or America/Montreal is a particular region’s history of past, present, and future changes to its offset-from-UTC. Anomalies such as Daylight Saving Time (DST) mean a change to the offset.
If you know all your inputs are in GMT/UTC, use OffsetDateTime. If the inputs may use time zones, parse as ZonedDateTime objects.
This input data format is terrible. If you have any control, use standard ISO 8601 formats instead when exchanging date-time values as text.
All this has been covered many times already on Stack Exchange. Please search more thoroughly before posting. And search Stack Overflow to learn more. I kept my Answer here brief, as this is a duplicate.
When parsing to a LocalDateTime, you're ignoring the offset (+0000), and I'm not sure if that's what you really want.
In this case, the +0000 offset means the date/time is October 27th 2017 at 02:29 AM in UTC. When you parse to a LocalDateTime, you're ignoring the offset (so it represents only "October 27th 2017 at 02:29 AM", not attached to any timezone) and comparing to your local date/time (or the current date/time in the JVM's default timezone).
If you want to make a comparison that also considers the offset, you can parse it to OffsetDateTime and convert to Instant to compare it with the actual UTC instant, regardless of the timezone.
Also, the month name is in English (I'm assuming it's English, but you can change this accordingly), so you must a java.util.Locale in the formatter (if you don't set a locale, it'll use the JVM default, and it's not guaranteed to always be English):
// parse to OffsetDateTime (use the same formatter)
String dateStr = "Oct 27 2017 02:29:00 GMT+0000";
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss zzzZ", Locale.US);
OffsetDateTime odt = OffsetDateTime.parse(dateStr, fmt);
// compare Instant's
System.out.println(odt.toInstant().isAfter(Instant.now()));
Although it works for you now, keep in mind that the default locale can be changed without notice, even at runtime. If your input has locale-sensitive date (such as month names), it's better to specify it as above.

PowerShell - Converting UTC To British Summer Time

I have written a simple function to convert any UTC time to current UK time (depending if Daylight Saving Time is being applied at the current season the result is either the same UTC or UTC + 1):
function Convert-UTCToUKTime
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)] $UTCTime
)
$UKTime = (Get-Date -Date $UTCTime)
if ($UKTime.IsDaylightSavingTime() -eq $true)
{
$UKTime = $UKTime.AddHours(1)
}
return $UKTime
}
I am also using this in the different function to get current UK time and it works just fine:
function Get-UKTime
{
[CmdletBinding()]
[OutputType([System.String])]
param
(
[Parameter(Mandatory = $true)] [String] $Format
)
$UKTime = Convert-UTCToUKTime -Time ((Get-Date).ToUniversalTime())
return $UKTime.ToString($Format)
}
However, when I try to pass the converting function a file created time (which is of course in UTC), it fails to recognize daylight saving time and therefore returns the UK time value with one hour behind (I tried to pass the exact same time by using Get-Date - there were no issues):
[System.IO.FileInfo] $FileInfo = $FullFileName
$FileCreatedTime = Convert-UTCToUKTime -UTCTime (($FileInfo.CreationTimeUTC)
I found the fix which helped me to get this working as I expect to (by converting the DateTime type to String before passing as a parameter):
$FileCreatedTime = Convert-UTCToUKTime -UTCTime (($FileInfo.CreationTimeUTC).ToString("yyyy/MM/dd hh:mm:ss"))
However, I am not really sure why this works. What is the difference here between using this with Get-Date and passing File Created time as a parameter as they both have the same DateTime type?
Any explanation would be really appreciated.
After extensive testing and discussion with peer colleagues, I think I have the answer to my original question now.
First of all, thanks to #PetSerAl for suggesting to use the Microsoft defined 'GMT Standard Time' time zone, which me and other users in the community found to be named controversially bearing in mind actual GMT has different offset in real life (hence the confusion), however, I found it to be exactly what I need to use in my case.
So why was I getting different results when passing the string and DateTime object of the same time in UTC? The answer is this:
Once I passed the object to the function which was a result of getting the time from file creation stamp in UTC, it was automatically initiated as proper UTC time type object, having the property .Kind set to value UTC (there are only two valid values for this property - UTC and Local for everything else). The function getting this parameter initially recognized the UTC type time and it could not detect the daylight saving time as UTC time zone simply does not support it.
In second case of sending the string to the function the main difference here was that once converting the actual string to the DateTime object inside my function it was using Get-Date, which by default instantiates the result object by using local machine's time (I am working in Lithuania) and therefore IsDaylightSavingTime() now could return the $True value as my local time zone does support it.
I noticed the incorrect assumption that GMT was British time this several years back (while working at Microsoft.) I think I filed a bug for it, but I'm not sure. It seems like you need a custom time zone.
I found this interesting post on defining custom time zones: http://subjectivecoder.blogspot.com.au/2013/04/creating-custom-windows-timezones.html. It should be possible to do this with PowerShell.

Powershell simplest method to get current time expressed as UTC

I have reviewed the post Creating a DateTime object with a specific UTC DateTime in PowerShell, but it does not seem to directly answer the question I am asking:
What is the most direct method in PowerShell (3.0) to return a sortable string representing "now" as UTC?
I expected the correct answer to be:
Get-Date -Format (Get-Culture).DateTimeFormat.UniversalSortableDateTimePattern
OR
get-date -format u
but this is not the case.
Example: At 1300 hrs (1pm) on September 1st, 2016 in the Pacific Time Zone during DST, I get the response:
2016-09-01 13:00:00Z (the local time with a "Z" appended)
when I was expecting:
2016-09-01 20:00:00Z (correct UTC/GMT time)
So basically, my code is just getting a string representing the "local" time and appending a "Z".
Now, I know I can manipulate to get to that point, but I'm looking for the minimal (simplest, cleanest) way to get here.
Bonus Points (as if they existed): How do I get that same, sortable result, but displaying with "UTC" and/or "GMT" as the suffix. Same minimal requirement.
Probably something like this:
[DateTime]::UtcNow.ToString('u')
Which is equivalent to:
[DateTime]::UtcNow.ToString((Get-Culture).DateTimeFormat.UniversalSortableDateTimePattern)
For the bonus, I think the most straightforward way is just to replace Z with UTC:
[DateTime]::UtcNow.ToString('u').Replace('Z','UTC')
I'm assuming you'll always want UTC since that what it seems like from your question. There doesn't appear to be a format string to get just the 3 letter time zone.
I tried this, and it also gives the result I want:
"[DateTime]::UtcNow.ToString('yyyyMMdd_HHmmss_UTC')"
It is showing time in the format 20180108_152407_UTC
so you can play with the date/time formatting as you wish basically

convert dateTime string to dateTime

the source for my integration is sending the date time as 07/01/2015 23:59:00 UTC and expects the output to be 2015-07-01T23:59:00-00:00.
in Oracle Service Bus, i used the functions fn-bea:dateTime-from-string-with-format("MM/dd/yyyy HH:mm:ss Z,data($products/startDate)) the output is 2015-07-01T23:59:00Z.
Is there a inbuilt function to get the above time pattern.
Use format-dateTime($dateTime, $pattern) with a matching date picture string. For example:
format-dateTime(current-dateTime(), "[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01][Z]")
Output (for my current time and timezone):
2015-06-30T23:45:51+02:00