RRR
RRR

Reputation: 4175

In PowerShell, how do I convert DateTime to UNIX time?

In PowerShell, how can I convert string of DateTime to sum of seconds?

Upvotes: 61

Views: 137713

Answers (22)

NathanWindisch
NathanWindisch

Reputation: 65

I can't think of a reason not to use static methods in this case (or ever to use Get-Date, really). Removing Get-Date from a two part of an expression can speed up the execution by ~x2, and using static methods for both can increase by ~x10, or even ~x20(!). Testing was done using Measure-These from Benchmark

The highest minimum amount of time spent for a test was 0.0153ms, and the lowest minimum time spent was 0.0009ms, a x17 increase in speed, all for the exact same result:

> [int64](((Get-Date "2024-01-01T00:00:00Z") - (Get-Date "1970-01-01")).TotalSeconds)
1704067200
> [int64](([DateTime]::Parse("2024-01-01T00:00:00Z") - [DateTime]::UnixEpoch).TotalSeconds)
1704067200
  1. Get-Date for both Unix epoch and a separate date parsed as a string:
# Measure-These -ScriptBlock { [int64](((Get-Date "2024-01-01T00:00:00Z") - (Get-Date "1970-01-01")).TotalSeconds) } -Count 100000

Average (ms) : 0.02248
Sum (ms)     : 2247.7003
Maximum (ms) : 3.0201
Minimum (ms) : 0.0153
  1. Get-Date for the string parsing, and the static [DateTime]::UnixEpoch:
# Measure-These -ScriptBlock { [int64](((Get-Date "2024-01-01T00:00:00Z") - [DateTime]::UnixEpoch).TotalSeconds) } -Count 100000 

Average (ms) : 0.01308
Sum (ms)     : 1308.0174
Maximum (ms) : 4.1801
Minimum (ms) : 0.0085
  1. [DateTime]::Parse for the string interpretation, and the static UnixEpoch again:
# Measure-These -ScriptBlock { [int64](([DateTime]::Parse("2024-01-01T00:00:00Z") - [DateTime]::UnixEpoch).TotalSeconds) } -Count 100000

Average (ms) : 0.00214
Sum (ms)     : 214.0234
Maximum (ms) : 3.0265
Minimum (ms) : 0.0012
  1. Using [DateTime]::UtcNow (or [DateTime]::Now) and UnixEpoch:
# Measure-These -ScriptBlock { [int64](([DateTime]::UtcNow - [DateTime]::UnixEpoch).TotalSeconds) } -Count 100000                       

Average (ms) : 0.00135
Sum (ms)     : 134.8408
Maximum (ms) : 0.6021
Minimum (ms) : 0.0009

I suspect the reason is partially that Now/UtcNow and UnixEpoch are static .NET CLR methods, which speeds up the runtime considerably. Not sure what Get-Date is doing to slow it down so much, though...

Upvotes: 0

Garric
Garric

Reputation: 734

culture-indiferent PowerShell handles milliseconds well

    [DateTimeOffset]::Now.ToUnixTimeMilliseconds()
    [math]::Round((Get-Date).ToUniversalTime().Subtract((Get-Date "01/01/1970")).TotalMilliseconds)
    [double]::Parse((get-date -uformat "%s"),[cultureinfo][system.threading.thread]::currentthread.currentculture).ToString().Replace(',','').Replace('.','').substring(0,13)
    [double]::Parse((get-date -date ([DateTime]::UtcNow) -uformat "%s"),[cultureinfo][system.threading.thread]::currentthread.currentculture).ToString().Replace(',','').Replace('.','').substring(0,13)
    [string](Get-Date (Get-Date).ToUniversalTime() -uformat '%s').ToString().Replace(',','').Replace('.','').substring(0,13)
    [math]::Round((([TimeSpan]((Get-Date(Get-Date).ToUniversalTime())-(New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0))).TotalMilliseconds))

For my codes, I use a reverse conversion script(time-zoned included):

    $VALstring = [DateTimeOffset]::Now.ToUnixTimeMilliseconds()
    try{
        $null=[bigint]$VALstring 
        try{
            $origin = New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0
            $unixTime = $origin.AddSeconds($VALstring)
            $unixTime=Get-Date $unixTime -Format "ddd, dd.MM.yyyy HH:mm:ss,fff"
        }catch{
            try{
                $unixTime = $origin.AddMilliseconds($VALstring)
                $unixTime=Get-Date $unixTime -Format "ddd, dd.MM.yyyy HH:mm:ss,fff"           
            }catch{
                $unixTime=''
            }
        }
        try{
            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
            $unixTimeZoned=$VALstring | epoch
            $unixTimeZoned=Get-Date $unixTimeZoned -Format "ddd, dd.MM.yyyy HH:mm:ss,fff"
        }catch{$unixTimeZoned=''}
    }catch{}
    "unixTime = $unixTime"
    "unixTimeZoned = $unixTimeZoned"

Upvotes: 0

Rade_303
Rade_303

Reputation: 905

If anyone is interested in getting milliseconds since Unix epoch, my approach is something like this

[int](Get-Date -UFormat %s) * 1000 + (Get-Date).Millisecond

Upvotes: -1

Mic Ho
Mic Ho

Reputation: 121

tested work well with different timezone:

(Get-Date).ToUniversalTime().Subtract((Get-Date "01/01/1970")).Totalseconds
# or
[DateTimeOffset]::Now.ToUnixTimeSeconds()

below is NOT recommend because it only works on timezone GMT+0

 Get-Date -UFormat %s

BTW, we can also verify the EPOCH UNIX time if you installed python:

python -c "import time;print(time.time())"

Upvotes: 1

silicontrip
silicontrip

Reputation: 1026

Not sure when -UFormat was added to Get-Date but it allows you to get the date and time in UNIX epoch timestamp format:

[int64](Get-Date -UFormat %s)

It's supported by both the PowerShell and PowerShell Core.

Upvotes: 36

VertigoRay
VertigoRay

Reputation: 6293

Signal15's answer is a bit verbose for me. I did it this way:

[int] (Get-Date (Get-Date).ToUniversalTime() -uformat '%s')

Upvotes: 1

Vesper
Vesper

Reputation: 18757

A culture-independent, and actually pretty fast answer:

[int64]([double]::Parse((get-date -uformat "%s"),[cultureinfo][system.threading.thread]::currentthread.currentculture))

This invokes some .NET "magic" when it comes to actually produce a formatted string, it gets converted to double using current thread's culture settings, then it converts to int64 which by default does exactly floor the double provided. Should you desire a UTC timestamp, use -date ([DateTime]::UtcNow) in get-date to use current UTC time as the time to convert.

[int64]([double]::Parse((get-date -date ([DateTime]::UtcNow) -uformat "%s"),[cultureinfo][system.threading.thread]::currentthread.currentculture))

PS: Unless you really need a string as your output, having an integer is overall better to your programming culture.

Upvotes: 1

marsze
marsze

Reputation: 17164

Late answer...

Hare are both convert functions ConvertTo-UnixTime & ConvertFrom-UnixTime for convenience (both pipeline capable)

function ConvertFrom-UnixTime () {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline, Position = 0)]
        [Int64]$UnixTime
    )
    begin {
        $epoch = [DateTime]::SpecifyKind('1970-01-01', 'Utc')
    }
    process {
        $epoch.AddSeconds($UnixTime)
    }
}

function ConvertTo-UnixTime {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline, Position = 0)]
        [DateTime]$DateTime
    )
    begin {
        $epoch = [DateTime]::SpecifyKind('1970-01-01', 'Utc')
    }
    process {
        [Int64]($DateTime.ToUniversalTime() - $epoch).TotalSeconds
    }
}

Upvotes: 0

Barbara
Barbara

Reputation: 41

For sending data to Grafana I needed the Unix Epoch time as 32 bit Integer from UTC. The best solution in the end was this:

$unixtime = (get-date -Date (get-date).ToUniversalTime() -UFormat %s).Substring(0,10)

This results in a string, but can easy converted to an integer:

[int]$unixtime = (get-date -Date (get-date).ToUniversalTime() -UFormat %s).Substring(0,10)

I tested this against an Ubuntu machine. The results from the commands above and the Linux command

date +%s

are identically.

Upvotes: 4

Ygramul
Ygramul

Reputation: 95

Here's a script which converts both TO and FROM CTIME that I've been using for a while (longer, because it was written for a "new to scripting" type crowd, with various comments.

# Here's a very quick variant to 'get the job done'
[Int64]$ctime=1472641743
[datetime]$epoch = '1970-01-01 00:00:00'
[datetime]$result = $epoch.AddSeconds($Ctime)

write-host $result

# A few example values for you to play with:
# 1290100140 should become ... 2010-11-18 17:09:00.000
# 1457364722 should become ... 2016-03-07 15:32:02.000
# 1472641743 should become ... 31/08/2016 11:09:03

# For repeated use / calculations, functions may be preferable. Here they are.

# FROM C-time converter function
# Simple function to convert FROM Unix/Ctime into EPOCH / "friendly" time
function ConvertFromCtime ([Int64]$ctime) {
    [datetime]$epoch = '1970-01-01 00:00:00'    
    [datetime]$result = $epoch.AddSeconds($Ctime)
    return $result
}

# INTO C-time converter function
# Simple function to convert into FROM EPOCH / "friendly" into Unix/Ctime, which the Inventory Service uses.
function ConvertToCTime ([datetime]$InputEpoch) {
    [datetime]$Epoch = '1970-01-01 00:00:00'
    [int64]$Ctime = 0

    $Ctime = (New-TimeSpan -Start $Epoch -End $InputEpoch).TotalSeconds
    return $Ctime
}

Hope that helps, especially if you just want something that's a little friendlier for beginners or so :).

Upvotes: 3

Andy McRae
Andy McRae

Reputation: 667

You can use the Uformat parameter of get-date. But first I like to be sure the date of a given workstation is correct (I consider a workstation connected to a company network where there is a server with a correct time set).

#Synchronize workstation time with server
cmd /c "sc config w32time start= auto"
cmd /c "w32tm /unregister"
cmd /c "w32tm /register"
cmd /c "net start w32time"
cmd /c 'tzutil.exe /s "W. Europe Standard Time"'
cmd /c 'reg add "HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation" /v DisableAutoDaylightTimeSet /t REG_DWORD /d 0 /f'  
cmd /c "net time \\full-servername.ru /set /yes"  

Then I get the actual unix timestamp to compare objects (accounts) between actual date and creation date (account deletion tasks when unix timestamp exceeds limit date)

#Get actual unix timestamp and compare it to something
$actual_date = (get-date -UFormat "%s")
$final_date = "some unix date of the database"
if(($final_date - $actual_date) -lt 0 ){
#make deletion task
}

Upvotes: 1

ravikanth
ravikanth

Reputation: 25830

PS H:\> (New-TimeSpan -Start $date1 -End $date2).TotalSeconds

1289923177.87462

New-TimeSpan can be used to do that. For example,

$date1 = Get-Date -Date "01/01/1970"
$date2 = Get-Date
(New-TimeSpan -Start $date1 -End $date2).TotalSeconds

Or just use this one line command

(New-TimeSpan -Start (Get-Date "01/01/1970") -End (Get-Date)).TotalSeconds

Upvotes: 59

Neal Garrett
Neal Garrett

Reputation: 185

Powershell

$epoch = (Get-Date -Date ((Get-Date).DateTime) -UFormat %s)

Upvotes: 7

miljbee
miljbee

Reputation: 350

This one should also work since javascript uses milliseconds since epoch :

ConvertTo-Json (Get-Date) | ? { $_ -Match '\(([0-9]+)\)' } | % { $Matches[1]/1000 }

Step by Step :

PS P:\> Get-Date

lundi 15 janvier 2018 15:12:22


PS P:\> ConvertTo-Json (Get-Date)
{
    "value":  "\/Date(1516025550690)\/",
    "DisplayHint":  2,
    "DateTime":  "lundi 15 janvier 2018 15:12:30"
}

PS P:\> (ConvertTo-Json (Get-Date)) -Match '\(([0-9]+)\)'
True
PS P:\> $Matches

Name                           Value
----                           -----
1                              1516025613718
0                              (1516025613718)

Upvotes: 1

Sean Staats
Sean Staats

Reputation: 297

I just wanted to present yet another, and hopefully simpler, way to address this. Here is a one liner I used to obtain the current Unix(epoch) time in UTC:

$unixTime = [long] (Get-Date -Date ((Get-Date).ToUniversalTime()) -UFormat %s)

Breaking this down from the inside out:

(Get-Date).ToUniversalTime()

This gets the current date/time in UTC time zone. If you want the local time, just call Get-Date. This is then used as input to...

[long] (Get-Date -Date (UTC date/time from above) -UFormat %s)

Convert the UTC date/time (from the first step) to Unix format. The -UFormat %s tells Get-Date to return the result as Unix epoch time (seconds elapsed since January 01, 1970 00:00:00). Note that this returns a double data type (basically a decimal). By casting it to a long data type, it is automatically converted (rounded) to a 64-bit integer (no decimal). If you want the extra precision of the decimal, don't cast it to a long type.

Extra credit

Another way to convert/round a decimal number to a whole number is to use System.Math:

[System.Math]::Round(1485447337.45246)

Upvotes: 10

Jim Moyle
Jim Moyle

Reputation: 675

Again comparing to http://www.unixtimestamp.com and building on others above

$date1 = (Get-Date -Date "01/01/1970").ToUniversalTime()
$date2 = (Get-Date).ToUniversalTime()
$epochTime = [Math]::Floor((New-TimeSpan -Start $date1 -End $date2).TotalSeconds)

Upvotes: 0

Sushena
Sushena

Reputation: 127

Below cmdlet will convert the windows uptime into Unix understandable epoch time format:

   $s=Get-WmiObject win32_operatingsystem | select csname,@{LABEL='LastBootUpTime';EXPRESSION{$_.ConverttoDateTime($_.lastbootuptime)}};
   [Math]::Floor([decimal](Get-Date($s.LastBootUpTime.ToUniversalTime()).ToUniversalTime()-uformat "%s"))

Upvotes: 1

user4003407
user4003407

Reputation: 22132

With .NET Framework 4.6 you can use ToUnixTimeSeconds method of DateTimeOffset class:

[DateTimeOffset]::Now.ToUnixTimeSeconds()

$DateTime = Get-Date #or any other command to get DateTime object
([DateTimeOffset]$DateTime).ToUnixTimeSeconds()

Upvotes: 65

jansohn
jansohn

Reputation: 2346

This one-liner works for me (compared it to http://www.unixtimestamp.com/)

[int64](([datetime]::UtcNow)-(get-date "1/1/1970")).TotalSeconds

For milliseconds

[int64](([datetime]::UtcNow)-(get-date "1/1/1970")).TotalMilliseconds

Upvotes: 23

Gary Pendlebury
Gary Pendlebury

Reputation: 385

I suggest the following, which is based on ticks (Int64), rather than seconds (Int32), to avoid the Year 2038 problem. [Math]::Floor is used, as Unix time is based on the number of whole seconds since the epoch.

[long][Math]::Floor((($DateTime.ToUniversalTime() - (New-Object DateTime 1970, 1, 1, 0, 0, 0, ([DateTimeKind]::Utc))).Ticks / [timespan]::TicksPerSecond))

Upvotes: 3

Signal15
Signal15

Reputation: 587

As mentioned, the UNIX Epoch is January 1st, 1970 at 12:00 AM (midnight) UTC. To get the current seconds-since-the-epoch in UTC in a whole-number I use this 80-character one-liner

$ED=[Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s"))

The code above is PowerShell 2.0 compliant & rounds-down (to ensure consistent behavior w/ UNIX)

Upvotes: 38

Keith Hill
Keith Hill

Reputation: 202072

To get seconds since 1970 independent of time zone, I would go with:

$unixEpochStart = new-object DateTime 1970,1,1,0,0,0,([DateTimeKind]::Utc)
[int]([DateTime]::UtcNow - $unixEpochStart).TotalSeconds

Upvotes: 18

Related Questions