В PowerShell, как мне преобразовать DateTime в UNIX время?

В PowerShell, как я могу преобразовать строку DateTime в сумму секунд?

21 ответ

Решение
PS H:\> (New-TimeSpan -Start $date1 -End $date2).TotalSeconds

1289923177.87462

New-TimeSpan может быть использован для этого. Например,

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

Или просто используйте эту однострочную команду

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

С.NET Framework 4.6 вы можете использовать ToUnixTimeSeconds метод DateTimeOffset учебный класс:

[DateTimeOffset]::Now.ToUnixTimeSeconds()

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

Как уже упоминалось, эпоха UNIX наступит 1 января 1970 года в 12:00 (полночь) по Гринвичу. Чтобы получить текущие секунды с начала эпохи в UTC для целого числа, я использую эту однострочную строку из 80 символов

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

Вышеприведенный код совместим с PowerShell 2.0 и округляется (для обеспечения согласованного поведения с UNIX)

Не уверен, когда -uformat был добавлен в get-date, но он позволяет использовать строки формата даты unix;

[int64](get-date -uformat %s)

Этот однострочник работает для меня (по сравнению с http://www.unixtimestamp.com/)

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

За миллисекунды

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

Чтобы получить секунды с 1970 года независимо от часового пояса, я бы использовал:

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

Я просто хотел представить еще один, и, надеюсь, более простой способ решения этой проблемы. Вот один вкладыш, который я использовал для получения текущего времени Unix(эпохи) в UTC:

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

Разбивая это изнутри:

(Get-Date).ToUniversalTime ()

Получает текущую дату / время в часовом поясе UTC. Если вы хотите местное время, просто позвоните в Get-Date. Это затем используется как вход для...

[long] (Get-Date -Date (дата и время UTC сверху) -UFormat %s)

Преобразуйте дату / время в формате UTC (с первого шага) в формат Unix. Параметр -UFormat% s указывает Get-Date возвращать результат как время эпохи Unix(секунды, прошедшие с 01 января 1970 г., 00:00:00). Обратите внимание, что это возвращает двойной тип данных (в основном, десятичный). Приведя его к длинному типу данных, он автоматически преобразуется (округляется) в 64-разрядное целое число (без десятичного числа). Если вам нужна дополнительная точность десятичного числа, не приводите его к длинному типу.

Дополнительный кредит

Другой способ преобразовать / округлить десятичное число до целого числа - это использовать System.Math:

[System.Math]::Round(1485447337.45246)

Powershell

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

Для отправки данных в Grafana мне нужно было время Unix Epoch как 32-битное целое число от UTC. Лучшим решением в итоге было следующее:

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

В результате получается строка, но ее можно легко преобразовать в целое число:

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

Я тестировал это на машине Ubuntu. Результаты приведенных выше команд и команды Linux

date +%s

идентичны.

Вот скрипт, который преобразует и в и из CTIME, который я использовал некоторое время (дольше, потому что он был написан для толпы типа "новичок в скрипте") с различными комментариями.

# Here's a very quick variant to 'get the job done'
[Int]$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 ([Int]$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'
    [int]$Ctime = ""

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

Надеюсь, это поможет, особенно если вы просто хотите что-то более дружелюбное для начинающих или около того:).

Я предлагаю следующее, которое основано на тиках (Int64), а не секундах (Int32), чтобы избежать проблемы 2038 года. [Math]::Floor используется, поскольку время Unix основано на количестве целых секунд с начала эпохи.

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

Это также должно работать, так как javascript использует миллисекунды с эпохи:

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

Шаг за шагом:

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)

Ниже командлет преобразует время безотказной работы Windows в понятный формат времени эпохи Unix:

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

Независимый от культуры и на самом деле довольно быстрый ответ:

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

Это вызывает некоторую «магию» .NET, когда дело доходит до фактического создания отформатированной строки, она преобразуется в double с использованием настроек языка и региональных параметров текущего потока, а затем преобразуется в int64, который по умолчанию точно перекрывает предоставленный double. Если вам нужна метка времени в формате UTC, используйте -date ([DateTime]::UtcNow) в get-date чтобы использовать текущее время в формате UTC в качестве времени для преобразования.

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

PS: Если вам действительно не нужна строка в качестве вывода, наличие целого числа в целом лучше для вашей культуры программирования.

Снова сравнивая с http://www.unixtimestamp.com/ и опираясь на другие выше

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

протестировано, хорошо работает с разными часовыми поясами:

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

ниже НЕ рекомендуется, поскольку он работает только в часовом поясе GMT+0.

       Get-Date -UFormat %s

Кстати, мы также можем проверить время EPOCH UNIX, если вы установили Python:

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

Вы можете использовать параметр Uformat команды get-date. Но сначала мне нужно убедиться, что дата данной рабочей станции верна (я рассматриваю рабочую станцию, подключенную к сети компании, где есть сервер с правильным установленным временем).

#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"  

Затем я получаю фактическую временную метку unix для сравнения объектов (учетных записей) между фактической датой и датой создания (задачи удаления учетной записи, когда временная метка unix превышает дату ограничения)

#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
}

Ответ Signal15 для меня немного многословен. Я сделал это так:

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

не зависящий от культуры PowerShell хорошо обрабатывает миллисекунды

          [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))

Для своих кодов я использую сценарий обратного преобразования (включая часовой пояс):

          $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"

Поздний ответ...

Заяц - обе функции преобразования ConvertTo-UnixTime & ConvertFrom-UnixTime для удобства (оба конвейера способны)

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
    }
}

Если кто-то заинтересован в получении миллисекунд со времен Unix, мой подход примерно такой:

      [int](Get-Date -UFormat %s) * 1000 + (Get-Date).Millisecond
Другие вопросы по тегам