Note: For convenience, PowerShell is used to demonstrate the behavior, but the question is about surprising behavior of the System.DateTime
.NET type, contrasted with type System.DateTimeOffset
.
There may be a good conceptual reason for this behavior, but it escapes me. If there is, it would be helpful to understand why and how to avoid this pitfall.
The following PowerShell snippet demonstrates round-trip conversion of a DateTime
instance expressed in local time via its Unix time equivalent:
# Get midnight 1 Jul 2018 in local time.
$date = Get-Date '2018-07-01'
# Convert to Unix time (seconds since midnight 1 Jan 1970 UTC)
# Note: In PowerShell Core this command could be simplified to: Get-Date -Uformat %s $date
$unixTime = [int] (Get-Date -Uformat %s $date.ToUniversalTime())
# Reconvert the Unix time stamp to a local [datetime] instance.
# Note that even though the input string is a UTC time, the cast creates
# a *local* System.DateTime instance (.Kind equals Local)
$dateFromUnixTime1 = ([datetime] '1970-01-01Z').AddSeconds($unixTime)
# Reconvert the Unix time stamp to a local [datetime] instance via
# a [System.DateTimeOffset] instance:
$dateFromUnixTime2 = ([datetimeoffset ] '1970-01-01Z').AddSeconds($unixTime).LocalDateTime
# Output the results
@"
original: $date
Unix time: $unixTime
reconstructed via [datetime]: $dateFromUnixTime1
reconstructed via [datetimeoffset]: $dateFromUnixTime2
"@
The above yields (on my US-English system in the Eastern Timezone):
original: 07/01/2018 00:00:00
Unix time: 1530417600
reconstructed via [datetime]: 06/30/2018 23:00:00
reconstructed via [datetimeoffset]: 07/01/2018 00:00:00
As you can see, the [datetime]
instance obtained via the ([datetime] '1970-01-01Z')
instance - whose .Kind
value is Local
, i.e., a local date - is off by 1 hour, whereas the [datetimeoffset]
-based calculation (which is UTC-based) works as expected.
I suspect that this is related to DST (daylight-saving time) - it wouldn't happen with 2018-12-01
, for instance - but I'm unclear why.