Why do I need to divide the timestamp by 1 billion? - postgresql

I'm using this public Postgres DB of NEAR protocol: https://github.com/near/near-indexer-for-explorer#shared-public-access
There is a field called included_in_block_timestamp whose "data type" = "numeric", and "length/precision" = 20.
This code works:
to_char(TO_TIMESTAMP("public"."receipts"."included_in_block_timestamp"/1000000000), 'YYYY-MM-DD HH:mm') as moment,
and so does this:
function convertTimestampDecimalToDayjsMoment(timestampDecimal: Decimal) {
const timestampNum = Number(timestampDecimal) / 1_000_000_000; // Why is this necessary?
console.log({ timestampNum });
const moment = dayjs.unix(timestampNum); // https://day.js.org/docs/en/parse/unix-timestamp
return moment;
}
For example, sometimes included_in_block_timestamp = 1644261932960444221.
I've never seen a timestamp where I needed to divide by 1 billion. Figuring this out just now was a matter of trial and error.
What's going on here? Is this common practice? Does this level of precision even make sense?

Timestamp units of measure in nanoseconds seems to be determined at the protocol-level as this appears in the docs here: https://docs.near.org/develop/contracts/environment/#environment-variables
and here: https://nomicon.io/RuntimeSpec/Components/BindingsSpec/ContextAPI
So yes, do take this into account before date-time conversions.

Related

How to format the Duration object in Swift

Swift released a new Duration object that is "a representation of high precision time."
I'm using it like this:
let clock = ContinuousClock()
let duration = clock.measure {
// Code or function call to measure here
}
print("Duration: \(duration)")
If the duration really short it prints out something like this:
8.2584e-05 seconds
Instead of scientific notation, I would like to always display as seconds: 0.000082584 seconds
Does anyone know how to always keep the format in seconds?
Just like Dates, Durations support the formatted method. You can give it either the TimeFormatStyle (time) or UnitsFormatStyle (units). For your desired format, it looks like the latter is more suitable. You basically want a fractionalPart that has a very large allowed length.
Though from my experiments, it still rounds everything to nanosecond-precision, even though Duration can support higher precisions. This is perhaps because nanoseconds is the smallest supported unit in Duration.UnitsFormatStyle.Unit.
For example:
let duration: Duration = .nanoseconds(1234)
print(
duration.formatted(.units(
width: .wide,
fractionalPart: .init(lengthLimits: 1...1000)
))
)
Output:
0.000001234 seconds
By default, this will also include hours and minutes if the duration is long enough. If you don't want that, pass allowed: [.seconds] as the first parameter:
duration.formatted(.units(
allowed: [.seconds],
width: .wide,
fractionalPart: .init(lengthLimits: 1...1000)
))

Result of adding second to date is one minute off; workaround

I'm adding a second to an instance of Foundation's date, but the result is off by an entire minute.
var calendar = Calendar(identifier: .iso8601)
calendar.locale = Locale(identifier: "en")
calendar.timeZone = TimeZone(identifier: "GMT")!
let date1 = Date(timeIntervalSinceReferenceDate: -62544967141.9)
let date2 = calendar.date(byAdding: DateComponents(second: 1),
to: date1,
wrappingComponents: true)!
ISO8601DateFormatter().string(from: date1) // => 0019-01-11T22:00:58Z
ISO8601DateFormatter().string(from: date2) // => 0019-01-11T21:59:59Z
Interestingly, one of the following makes the error go away:
round time interval since reference date
don't add time zone to calendar
set wrappingComponents to false (even though it shouldn't wrap in this case)
I don't really need sub-second precision in my code, so I created this extension that allows me to discard it.
extension Date {
func roundedToSeconds() -> Date {
return Date(timeIntervalSinceReferenceDate: round(timeIntervalSinceReferenceDate))
}
}
I want to know this:
Why does this error happen?
Am I doing something wrong?
Is there any issue with my workaround?
Why does this error happen?
I would say this is a bug in Core Foundation (CF).
Calendar.date(byAdding:to:wrappingComponents:) calls down to the internal Core Foundation function _CFCalendarAddComponentsV, which in turn uses the ICU Calendar C API. ICU represents a time as an floating-point number of milliseconds since the Unix epoch, while CF uses a floating-point number of seconds since the NeXT reference date. So CF has to convert its representation to ICU's representation before calling into ICU, and convert back to return the result to you.
Here's how it converts from a CF timestamp to an ICU timestamp:
double startingInt;
double startingFrac = modf(*atp, &startingInt);
UDate udate = (startingInt + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
The modf function splits a floating-point number into its integer and fractional parts. Let's plug in your example date:
var startingInt: Double = 0
var startingFrac: Double = modf(date1.timeIntervalSinceReferenceDate, &startingInt)
print(startingInt, startingFrac)
// Output:
-62544967141.0 -0.9000015258789062
Next, CF calls __CFCalendarAdd to add one second to -62544967141. Note that -62544967141 lies in the round one-minute interval -62544967200 ..< -62544967140.0. So when CF adds one second to -62544967141, it gets -62544967140, which would be in the next round one-minute interval. Since you specified wrapping components, CF isn't allowed to change the minute part of the date, so it wraps back to the beginning of the original round one-minute interval, -62544967200.
Finally, CF converts the ICU time back to a CF time, adding in the fractional part of the original time:
*atp = (udate / 1000.0) - kCFAbsoluteTimeIntervalSince1970 + startingFrac + (nanosecond * 1.0e-9);
So it returns -62544967200 + -0.9000015258789062 = -62544967200.9, exactly 59 seconds earlier than the input time.
Am I doing something wrong?
No, the bug is in CF, not in your code.
Is there any issue with my workaround?
If you don't need sub-second precision, your workaround should be fine.
I can reproduce it with more recent dates but so far only with negative reference dates, e.g. Date(timeIntervalSinceReferenceDate: -1008899941.9), which is 1969-01-11T22:00:58Z.
Any negative timeIntervalSinceReferenceDate in the last second of a minute interval should cause the problem. The bug effectively makes the first round whole minute prior to time 0 span from -60.99999999999999 through -1.0, but it should span from -60.0 through -5e324. All more-negative round minute intervals are similarly offset.

What type to use for timeIntervalSince1970 in ms?

I need time since Epoch in ms for an API request, so I'm looking to have a function that converts my myUIDatePicker.date.timeIntervalSince1970 into milliseconds by multiplying by 1000. My question is what should the return value be?
Right now I have
func setTimeSinceEpoch(datePicker: UIDatePicker) -> Int {
return Int(datePicker.date.timeIntervalSince1970 * 1000)
}
Will this cause any issues? I need an integer, not a floating point, but will I have issues with overflow? I tested it out with print statements and it seems to work but I want to find the best way of doing this.
Looking at Apple Docs:
var NSTimeIntervalSince1970: Double { get }
There is a nice function called distantFuture. Even if you use this date in you func the result will be smaller then the max Int.
let future = NSDate.distantFuture() // "Jan 1, 4001, 12:00 AM"
print((Int(future.timeIntervalSince1970) * 1000) < Int.max) // true
So, until 4001 you're good to go. It will work perfectly on 64-bits systems.
Note: If your system supports iPhone 5 (32-bits) it's going to get an error on pretty much any date you use. Int in Iphone 5 corresponds to Int32.
Returning an Int64 is a better approach. See this.

What is the most efficient way to convert an eight digit number to a date?

I am using ColdFusion 9.0.1 and some database that I cannot change.
I am accessing a database that stores a date as an eight digit numeric with zero decimal places like this:
YYYYMMDD
I need to be able to read the date, add and subtract days from a date, and create new dates. I am looking for a ColdFusion solution to efficiently (not much code) to convert the date to our standard format, which is
MM/DD/YYYY
And then convert it back into the database's format for saving.
I need to code this in such a way that non-ColdFusion programmers can easily read this and use it, copy and modify it for other functions (such as adding a day to a date). So, I am not looking for the most least amount of code, but efficient and readable code.
Can you suggest anything that would make this code block more flexible, readable, or more efficient (less code)?
<cfscript>
// FORMAT DB DATE FOR BROWSER
DateFromDB = "20111116";
DatedToBrowser = createBrowserDate(DateFromDB);
writeOutput(DatedToBrowser);
function createBrowserDate(ThisDate) {
ThisYear = left(ThisDate, 4);
ThisMonth = mid(ThisDate, 4, 2);
ThisDay = right(ThisDate, 2);
NewDate = createDate(ThisYear, ThisMonth, ThisDay);
NewDate = dateFormat(NewDate, "MM/DD/YYYY");
return NewDate;
}
// FORMAT BROWSER DATE FOR DB
DateFromBrowser = "11/16/2011";
DateToDB = createDBDate(DateFromBrowser);
writeDump(DateToDB);
function createDBDate(ThisDate) {
ThisYear = year(ThisDate);
ThisMonth = month(ThisDate);
ThisDay = day(ThisDate);
NewDate = "#ThisYear##ThisMonth##ThisDay#";
return NewDate;
}
</cfscript>
First find who ever did the database and kick them in the nads...
Personally I'd Convert with sql so my code only dealt with date objects.
Select Convert(DateTime, Convert(VarChar(8),DateTimeInventedByIdjitColumn))
From SomeTable
As stated by our peers, store dates as dates.
'08/06/2011' could be 8th of june of the 6th of August depending on locale.
20111643 is a valid integer..
Not using a proper date type is just a massive collection of features and bugs that at best are waiting to happen.
You can actually rewrite each function into 1 line of code.
function createBrowserDate(ThisDate) {
return mid(ThisDate,4,2) & "/" & right(ThisDate,2) & "/" & left(ThisDate,4);
}
and
function createDBDate(ThisDate) {
return dateFormat( ThisDate, "YYYYMMDD" );
}
Don't keep dates as strings - keep dates as dates and format them when you need to.
If you can't correct the database to use actual date columns (which you should if you can), then you can use these two functions to convert to/from YYYYMMDD and a date object:
function parseYMD( YYYYMMDD )
{
if ( ! refind('^\d{8}$' , Arguments.YYYYMMDD ) )
throw "Invalid Format. Expected YYYYMMDD";
return parseDateTime
( Arguments.YYYYMMDD.replaceAll('(?<=^\d{4})|(?=\d{2}$)','-') );
}
function formatYMD( DateObj )
{
return DateFormat( DateObj , 'yyyymmdd' );
}
By using date objects it means that any level of developer can work with them, without needing to care about formatting, via built-in functions like DateAdd, DateCompare, and so on.
I'm not a regular expression fan since it's not that readable to me.
Since you're using CF9, I'd typed the argument and specify the returntype of the functions to be even more readable for the next person picking up your code.
First, right after I read the date from DB, I'd parse it to a Date object using parseDBDate()
Date function parseDBDate(required String dbDate)
{
var yyyy = left(dbDate, 4);
var mm = mid(dbDate, 4, 2);
var dd = right(dbDate, 2);
return createDate(yyyy , mm, dd);
}
Once you have the date object, you can use all those built-in Date functoin like DateAdd() or DateDiff().
Call browserDateFormat() right before you need to display it.
String function browserDateFormat(required Date date)
{
return dateFormat(date, "MM/DD/YYYY");
}
Call dBDateFormat() inside <cfqueryparam value=""> when it's time to persist to DB
String function dBDateFormat(required Date date)
{
return dateFormat(date, "YYYYMMDD");
}
One liner :)
myDateString = "20110203";
myCfDate = createObject("java","java.text.SimpleDateFormat").init("yyyyMMdd").parse(myDateString,createObject("java","java.text.ParsePosition").init(0*0));
If you want to parse different patterns, change "yyyyMMdd" to any other supported pattern.
http://download.oracle.com/javase/1.5.0/docs/api/java/text/SimpleDateFormat.html
The ParsePosition is used to say where to start parsing the string.
0*0 is shorthand for JavaCast("int",0) - in the Adobe cf engine, 0 is a string, until you apply math to it, then it becomes a Double, which the ParsePosition constructor supports. Technically, it constructs with an int, but cf is smart enough to downgrade a Double to an int.
http://download.oracle.com/javase/1.5.0/docs/api/java/text/ParsePosition.html

KRL: Comparing two timestamps

I have two timestamps created with time:now() (one stored in an app variable from the past, one the current time). I need to find the difference between them (preferably in minutes). How do I do that?
I've tried this syntax, but the parser didn't like it:
diff = time:now() - original_time;
time:compare() doesn't give me enough information, and time:add() is the opposite of what I need. There don't seem to be any other applicable time functions documented.
The time functions return a time string, not a time object. To calculate time elapsed, you will have to convert your time string into epoch time (seconds since 1970..). Fortunately, epoch time is one of the formats supported by strftime.
foo = time:now();
efoo = time:strftime(foo,"%s);
The minus operator is actually sensitive to a leading whitespace. It's on the list of things to work out of the parser, but I just haven't had time to get to it. Here is a working rule:
rule first_rule {
select when pageview ".*" setting ()
pre {
foo = time:now();
bar = time:add(foo,{"minutes": -5});
ebar = time:strftime(bar,"%s");
efoo = time:strftime(foo,"%s");
diff = efoo-ebar;
}
notify("-5 minutes in seconds", diff) with sticky = true;
}