Timestamp to ISO 8601 in Lua - nginx

How would you convert a timestamp to an ISO 8601 format (such as 2009-01-28T21:49:59.000Z) in Lua?
I'm specifically trying to do it by using the HttpLuaModule in Nginx.

Try os.date("!%Y-%m-%dT%TZ") or os.date("!%Y-%m-%dT%TZ",t) if t has the date in seconds since the epoch.

You asked to include milliseconds, so there is a little gymnastics involved because the os.date format doesn't permit milliseconds.
This works when running in Nginx (which was the context of your question)
-- Return a ISO 8061 formatted timestamp in UTC (Z)
-- #return e.g. 2021-09-21T15:20:44.323Z
local function iso_8061_timestamp()
local now = ngx.now() -- 1632237644.324
local ms = math.floor((now % 1) * 1000) -- 323 or 324 (rounding)
local epochSeconds = math.floor(now)
return os.date("!%Y-%m-%dT%T", epochSeconds) .. "." .. ms .. "Z" -- 2021-09-21T15:20:44.323Z
end
Note the useful date format reference here: https://developpaper.com/lua-os-date-notes/

Or you can use:
local now_date_time = os.date("!%Y%m%dT%H%M%S") --> For date_time: 20191015T042028Z
local now_date = os.date("!%Y%m%d") --> For only date: 20191015

Related

Round back to quarter-hour in Mulesoft Dataweave

I have a Mule Server 4.3.0 EE application, and in it I want to round a DateTime to its most recent quarter-hour, with the result also being a DateTime. Some examples:
if the input is 9:18:32 AM, then the output is 9:15:00 AM the same day
if the input is 9:33:33 AM, then the output is 9:30:00 AM the same day
if the input is 9:59:58 AM, then the output is 9:45:00 AM the same day
if the input is 10:00:00 AM, then the output is 10:00:00 AM the same day
In this application, the input will always be in New York time, with DST in effect or not depending on the time of year.
Here's what I've come up with so far. Keep the date and hour, truncate the minutes to the nearest 15, set the seconds to zero, and keep the time zone. (There's a special case for '00' minutes because it won't convert if the minutes are a single '0'.)
I know newer Mule versions have the Dates package which would make this much more elegant, but upgrading isn't currently an option for me. Is this about as good as the code can be for those requirements, or is there a better way to do this without upgrading Mule? Thank you.
%dw 2.0
import * from dw::core::Strings
output application/json
fun roundBack(inputTime: DateTime): DateTime =
(inputTime[0 to 13] ++
(if (inputTime.minutes < 15) '00' else (inputTime.minutes - mod(inputTime.minutes, 15) as String)) ++
':00' ++
inputTime[-6 to -1]
) as DateTime
I believe that the logic is good but the implementation is fragile because it depends on auto coercions (DateTime to Strings when using the range selector []). It is better for me to be explicit in the conversions to avoid issues caused by unexpected defaults formats and warnings in the editor:
%dw 2.0
import * from dw::core::Strings
output application/json
fun roundBack(inputTime: DateTime): DateTime =
(
inputTime as String {format: "yyyy-MM-dd HH:"}
++ (if (inputTime.minutes < 15)
'00'
else (inputTime.minutes - mod(inputTime.minutes, 15)) as String
)
++':00'
++ inputTime as String {format: "xxx"}
) as DateTime {format: "yyyy-MM-dd HH:mm:ssxxx"}
---
roundBack(|2020-10-01T23:57:59-04:00|)
Output: "2020-10-01 23:45:00-04:00"

moment toISOstring without modifying date

I have a date like "Thu Sep 01 2016 00:00:00 GMT+0530 (IST)" which I need to send to server as ISO-8601 utc time. I tried like :
moment(mydate).toISOString()
moment.utc(mydate).toISOString()
moment(mydate).utcOffset("+00:00").toISOString()
but I am getting the result like
2016-08-31T18:30:00.000Z
which is 1day behind my intended time. So what can I do to make moment ignore my local timezone and see it as UTC?
Edit:
The expected output is
2016-09-01T18:30:00.000Z
And no, the initial input isn't a string rather a javascript "new Date()" value.
Reason this happens:
This happens because .toISOString() returns a timestamp in UTC, even if the moment in question is in local mode. This is done to provide consistency with the specification for native JavaScript Date .toISOString()
Solution:
Use the same function and pass true value to it. This will prevent UTC Conversion.
moment(date).toISOString(true)
const date = new Date("2020-12-17T03:24:00");
const dateISOStringUTC = moment(date).toISOString();
const dateISOString = moment(date).toISOString(true);
console.log("Converted to UTC:" + dateISOStringUTC)
console.log("Actual Date value:" + dateISOString)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
I take the same problem today and find the solution.
Here is the solution: moment(date,moment.ISO_8601)
var date = new Date();
console.log("Original Date");
console.log(date);
console.log("After Moment Format");
console.log(moment(date,moment.ISO_8601));
Test Execution:
Moment Documentation: MomentJs

Joda DateTime output unexpected difference from gmt

My code:
val pattern = "MM-dd-yy"
val t = DateTime.parse("07-01-86", DateTimeFormat.forPattern(pattern)).toDateTime(DateTimeZone.forID("GMT"))
val z = t.getMillis.asInstanceOf[Long]
println("ms= "+z) // expected output: 520560000000 actual output: 520578000000
Several online GMT date converters give a different millis output than DateTime. Anyone know why?
In your solution your local time zone is implicitly used when parsing the date time. You should use
val t = DateTime.parse("07-01-86", DateTimeFormat.forPattern(pattern).withZoneUTC())
to force the DateTime to be created in the UTC zone. Then, the millis is 520560000000. No need to execute toDateTime(DateTimeZone) on it any more.
Otherwise, with your construction
val t = DateTime.parse("07-01-86", DateTimeFormat.forPattern(pattern)).toDateTime(DateTimeZone.forID("GMT"))
the DateTime will be first created in your local TZ (ie. midnight of 07-01-86 in your TZ) and then "cast" to UTC, but preserving the timestamp (ie. it will be the same timestamp, but interpreted in UTC, so the time part and the day part will change depending on your local TZ offset).
Example (my TZ is +02:00):
DateTime.parse("07-01-86", DateTimeFormat.forPattern(pattern)) // --> 1986-07-01 00:00 (+02:00)
.toDateTime(DateTimeZone.forID("GMT")) // --> 1986-06-30 22:00 (UTC)
I assumed you are OK with using UTC over GMT but there's also
DateTimeFormat.forPattern(pattern).withZone(...)
where you can provide your desired zone.

Coldfusion calculate accountExpires

I'm trying to get all the accounts that have EXPIRED using accountExpires attribute in Active Directory.
As the attribute type is Int8 (64-bit integer) and coldfusion does not support such long integer, I am having a hard time getting this to work.
Is there a function or some sort that I can use to acheive the above?
Thanks!
A 64 bit integer in Java is a java.lang.Long. Longs are implicitly converted to Integers in ColdFusion.
accountExpires is a windows file time structure representing the number of 100-nanosecond intervals since January 1, 1601. This thread shows how we can get a windows file time to date:
long diff1601to1970 = 315532800 * 1000000000; // <-- diff in nanoseconds(1/1/1601 to 1/1/1970)
long currentFrom1970 = System.currentTimeMillis() * 1000000;
long currentFrom1601 = diff1601to1970 + currentFrom1970;
Which allows us to do the following in ColdFusion:
accountExpiresFileTime = 129407978957060010;
date = createObject("java", "java.util.Date").init(
(accountExpiresFileTime-116444736000000000)/10000
);
Hopefully that helps.

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

In PowerShell, how can I convert string of DateTime to sum of seconds?
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
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()
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)
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.
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
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
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)
Powershell
$epoch = (Get-Date -Date ((Get-Date).DateTime) -UFormat %s)
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))
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 :).
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.
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"))
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)
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)
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
}
Signal15's answer is a bit verbose for me. I did it this way:
[int] (Get-Date (Get-Date).ToUniversalTime() -uformat '%s')
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
}
}
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.

Resources