22

I am parsing an SQLite database using the PowerShell SQLite module, and a couple of the return values are created and modified, both of which are in Unix time.

What I would like to do is somehow convert that into "human time". I have removed some of the other SQL queries for ease of reading.

Import-Module SQLite
mount-sqlite -name GoogleDrive -dataSource E:\Programming\new.db
$cloud_entry = Get-ChildItem GoogleDrive:\cloud_entry

foreach ($entry in $cloud_entry)
{
    $entry.created
}

The output looks like a large column of Unix timestamps:

1337329458

Update: I ultimately went with the following:

$ctime = $entry.created
[datetime]$origin = '1970-01-01 00:00:00'
$origin.AddSeconds($ctime)
5
  • What you went with is ambiguous, because something like [datetime] '1970-01-01 00:00:00' creates a [datetime] instance whose .Kind property is Unspecified. By contrast, the start of Unix epoch time is unambiguously UTC. Commented Aug 8, 2019 at 23:48
  • 1
    @Thomas [datetime] '1970-01-01Z', which gives you a Local [datetime] instance; if you need a Utc instance, use ([datetime] '1970-01-01Z').ToUniversalTime() Commented May 4, 2020 at 9:10
  • @mklement0 Using a UTC start time for a value during daylight saving time is giving me a result that is off by an hour (the DST offset). I think using that method is doing the time zone calculation based on the start datetime, instead of the ending datetime. Commented Aug 26, 2021 at 0:17
  • @brianary You're correct: the correct solution is to get a Utc [datetime] instance, add the Unix epoch time (in seconds) to it, and then convert to local time: ([datetime] '1970-01-01Z').ToUniversalTime().AddSeconds($ctime).ToLocalTime(). Alternatively, using [datetimeoffset] (which is preferable in general): [datetimeoffset] '1970-01-01Z').AddSeconds($ctime).LocalDateTime Commented Aug 26, 2021 at 1:36
  • @mklement0 Just to clarify, a UTC DateTime doesn't seem to work without some extra confusing steps, see the further discussion below, stackoverflow.com/a/10781745/54323 Commented Aug 28, 2021 at 21:02

13 Answers 13

32

Use:

# Creates a timestamp representation in UTC. Use .LocalDateTime for local time.
(([System.DateTimeOffset]::FromUnixTimeSeconds($unixTime)).DateTime).ToString("s")

FromUnixTimeMilliseconds is also available.

ToString("s"): Sortable: "The pattern reflects a defined standard (ISO 8601)"

Ref.: Standard Date and Time Format Strings, The Sortable ("s") Format Specifier

Sign up to request clarification or add additional context in comments.

6 Comments

I feel stupid knowing that for the past years I've used [System.DateTime]::Parse('1-1-1970).AddSeconds($epoch) instead of DateTimeOffset
No worries, it looks like the method is new as of .net 4.6!
This doesn't seem to work. For a value of 1629937097, I'm getting 2021-08-26T00:18:17 instead of 2021-08-26T17:18:17 (see epochconverter.com or a similar reference converter).
@Fredrick It looks like I can use (([System.DateTimeOffset]::FromUnixTimeSeconds($unixTime)).DateTime.ToLocalTime()).ToString("s")
@brianary, [System.DateTimeOffset]::FromUnixTimeSeconds($unixTime).LocalDateTime.ToString("s") is simpler to get a representation in local time. Fredrick: the .DateTime property of [datetimeoffset] instances returns an ambiguous [datetime] instance, (its .Kind property value is Unspecified), which in this case happens to create the same string representation as UTC; however, if the intent is to create a UTC representation, it's better to use .UtcDateTime to avoid ambiguity.
|
31

See Convert a Unix timestamp to a .NET DateTime.

You can easily reproduce this in PowerShell.

$origin = New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0
$whatIWant = $origin.AddSeconds($unixTime)

11 Comments

[datetime]$origin = '1970-01-01 00:00:00' works just as well, and is maybe a little easier to understand
I'm getting this error: Any ideas? Cannot convert argument "0", with value: "", for "AddSeconds". Some of the values are "null", in that some of the items in the database are not assiged a created/modified date. I'm assuming this is where that error is coming from.
The time zone is going to be wrong unless you add .ToLocalTime() to the end of that second line. You can't use [datetime]'1970-01-01Z' because that'll do the time zone offset of the start time, which will be off during daylight savings.
Good point, @brianary: [datetime] '1970-01-01Z' by itself isn't enough, because it returns a Local [datetime] instance, which locks in the DST offset at the start time. Instead, use ([datetime] '1970-01-01Z').ToUniversalTime().AddSeconds($unixTime) to get the time as a UTC time stamp, and ([datetime] '1970-01-01Z').ToUniversalTime().AddSeconds($unixTime).ToLocalTime() to convert to a Local one. Or, using [datetimeoffset], which is preferable in general: ([datetimeoffset] '1970-01-01Z').AddSeconds($unixTime), then access .UtcDateTime or .LocalDateTime, as needed.
@mklement0 This works fine (Get-Date 1970-01-01).AddSeconds($unixTime).ToLocalTime(), without the confusion of code creating a UTC DateTime and then converting that to UTC again. The DateTimeOffset approach also gave me the wrong answer.
|
19
Function Convert-FromUnixDate ($UnixDate) {
   [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($UnixDate))
}

$niceTime = Convert-FromUnixDate $ctime

PS C:\> $niceTime

Friday, 18 May 2012 8:24:18 p.m.

Comments

8
$date = get-date "1/1/1970"
$date.AddSeconds($unixTime).ToLocalTime()

Comments

4

A simple one-liner:

(Get-Date "1970-01-01 00:00:00.000Z") + ([TimeSpan]::FromSeconds($unixTime))

Comments

4

Not bringing anything new to the table, but a pipable version of Fredrics answer:

function epoch() { 
    Param( 
        [Parameter(ValueFromPipeline)]$epochTime,
        [Switch]$Ms
    ) 
    Process { 
        if ($Ms) {
            [System.DateTimeOffset]::FromUnixTimeMilliseconds($epochTime)
        } else {
            [System.DateTimeOffset]::FromUnixTimeSeconds($epochTime)
        }
    } 
}
"1628043561861" | epoch -Ms

DateTime      : 04.08.2021 02:19:21
UtcDateTime   : 04.08.2021 02:19:21
LocalDateTime : 04.08.2021 04:19:21
Date          : 04.08.2021 00:00:00
Day           : 4
DayOfWeek     : Wednesday
DayOfYear     : 216
Hour          : 2
Millisecond   : 861
Minute        : 19
Month         : 8
Offset        : 00:00:00
Second        : 21
Ticks         : 637636403618610000
UtcTicks      : 637636403618610000
TimeOfDay     : 02:19:21.8610000
Year          : 2021

Comments

3

I know this is a super old question, but just wanted to share that Powershell 7's Get-Date has native support for converting Unix time now (which I discovered thanks to this question). By default, it will convert it to local time.

PS> Get-Date -UnixTimeSeconds 1338194440

Monday, May 28, 2012 4:40:40 AM

PS> (Get-Date -UnixTimeSeconds 1338194440).Kind

Local

If you want it in UTC, just add -AsUTC to the command.

PS> Get-Date -UnixTimeSeconds 1338194440 -AsUTC

Monday, May 28, 2012 8:40:40 AM

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-date?view=powershell-7.3#example-9-convert-a-unix-timestamp

Comments

2

The DateTime type in PowerShell 7 has a static UnixEpoch value defined, so this can be done even more tersely now:

[DateTime]::UnixEpoch.AddSeconds($unixTime)

Note: This was introduced in .NET Core 2.1, so I believe it is applicable to PowerShell versions since 6.1.

Comments

1
$ctime = $entry.created
[datetime]$origin = '1970-01-01 00:00:00'
$origin.AddSeconds($ctime)

Comments

1

I wanted to be sure that I was calculating from UTC, so I added the SpecifyKind:

$epochStart = New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0
$epochStart = [DateTime]::SpecifyKind($epochStart,[DateTimeKind]::Utc)

$DateTimeUTC = $epochStart.AddSeconds($UnixTimestamp)

1 Comment

Good idea to request a UTC time, but you can do that simply by passing another argument to the New-Object call: New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0, Utc
1

I found that neither of the suggested solutions solved my needs. So I adjusted and propose the following:

function ConvertFrom-UnixTime {
    [CmdletBinding(DefaultParameterSetName = "Seconds")]
    param (
        [Parameter(Position = 0, 
            ValueFromPipeline = $true, 
            Mandatory = $true,
            ParameterSetName = "Seconds")]
        [int]
        $Seconds,

        [Parameter(Position = 0, 
            ValueFromPipeline = $true, 
            Mandatory = $true, ParameterSetName = "Miliseconds")]
        [bigint]
        $Miliseconds
    )
    Begin {
        $date = (Get-Date "1970-01-01 00:00:00.000Z")
    }
    Process {
        switch ($PSCmdlet.ParameterSetName) {
            "Miliseconds" {
                $date = $date.AddMilliseconds($Miliseconds)
            }
            Default {
                $date = $date.AddSeconds($Seconds);
            }
        }
    }
    End {
        $date
    }
}
Set-Alias -Name epoch -Value ConvertFrom-UnixTime

Usage:

1633694244| epoch
1633694244565 | epoch

Both outputs:

8. oktober 2021 12:57:24

1 Comment

Time zone in function. It's great. The bulky function is easily reduced if desired. Thank you.
0

As of PowerShell 7.1, you can use -UnixTimeSeconds follows...

PS> Get-Date -UnixTimeSeconds 0 -AsUTC
Thursday, January 1, 1970 12:00:00 AM

PS> Get-Date -UnixTimeSeconds 1 -AsUTC
Thursday, January 1, 1970 12:00:01 AM

PS> Get-Date -UnixTimeSeconds 2 -AsUTC
Thursday, January 1, 1970 12:00:02 AM

Comments

0

Everything I tried returned an error that the unix date was 'out of range'. Here is what finally worked. After edits. Thanks to Kumpf. :)

PS> get-date ((Get-Date "1970-01-01 00:00:00.000Z") + ([TimeSpan]::FromSeconds($unixTime))) -uformat "%m/%d/%Y %T"

11/05/2024 06:10:56

Borrowed from miljbee and Peter Mo

1 Comment

Year 0001 might be a little earlier than you wanted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.