В 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