Question
· Aug 14

Any Better Way to Strip the Fractions of Seconds from a Posix Time?

Is there a better way (i.e., without string commands) to remove the fractions of seconds from a %Library.PosixTime value?

This works, but seems inefficient:

set posix = 1154669852181849976
w ##class(%Library.PosixTime).LogicalToTimeStamp(posix)
2025-05-27 12:06:15.003
set str = ##class(%Library.PosixTime).LogicalToTimeStamp(posix)
set stripped = $P(str,".",1)
w ##class(%Library.PosixTime).TimeStampToLogical(stripped)
1154669852181846976
set newposix = ##class(%Library.PosixTime).TimeStampToLogical(stripped)
w ##class(%Library.PosixTime).LogicalToTimeStamp(newposix)
2025-05-27 12:06:15

Note that I don't need the last string output; the value stored in "newposix" is what I want to retain.

Thanks in advance

Product version: IRIS 2024.1
$ZV: IRIS for Windows (x86-64) 2024.1.1 (Build 347U) Thu Jul 18 2024 17:35:51 EDT
Discussion (7)2
Log in or sign up to continue

First step: create your own method, for example

Class DC.Unix [ Abstract ]
{
/// Convert Posix time into Timestamp
/// 
/// posix: posix time
///    df: date format
///    tf: time format
///    dp: decimal places
ClassMethod PosixToTimeStamp(posix, df = 3, tf = 1, dp = 0)
{
	set posix=posix-1152921504606846976/1E6
	quit $zdt(posix\86400+47117_","_(posix#86400),df,tf,dp)
}
}

Next step, if you need more speed, instead of the parameters <df> and <tf> use constants and remove <dp>. The very last step: shorten the method name from PosixToTimeStamp() to P2TS()

This way I got the (nearly) the same times as with (%Library.PosixTime).LogicalToTimeStamp, but without the need for string manipulation 

ICINDY:USER>k

ICINDY:USER>set posix = 1154669852181849976

ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(%Library.PosixTime).LogicalToTimeStamp(posix) } w $zh-t
.902538
ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(%Library.PosixTime).LogicalToTimeStamp(posix) } w $zh-t
.90609
ICINDY:USER>

ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(DC.Unix).PosixToTimeStamp(posix) } w $zh-t
.934834
ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(DC.Unix).PosixToTimeStamp(posix) } w $zh-t
.944418
ICINDY:USER>

ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(DC.Unix).P2TS(posix) } w $zh-t
.913609
ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(DC.Unix).P2TS(posix) } w $zh-t
.905303
ICINDY:USER>

ICINDY:USER>w $zv
IRIS for UNIX (Ubuntu Server LTS for x86-64) 2021.2 (Build 649U) Thu Jan 20 2022 08:49:51 EST
ICINDY:USER>w x
2025-05-27 12:06:15
ICINDY:USER>
#Include %sqlx
set newposix $$$sqlxPosixTimeEncode(+$p($$$sqlxPosixTimeDecode(posix),".",1))

Сheck:

for posix = 1154669852181849976, -6979664624441081856, 1406323805406846975 {

  set newposix $$$sqlxPosixTimeEncode(+$p($$$sqlxPosixTimeDecode(posix),".",1))

  write ##class(%PosixTime).LogicalToTimeStamp(posix),!,
        ##class(%PosixTime).LogicalToTimeStamp(newposix),!!
}

2025-05-27 12:06:15.003
2025-05-27 12:06:15
 
0001-01-01 00:00:00
0001-01-01 00:00:00
 
9999-12-31 23:59:59.999999
9999-12-31 23:59:59

Hi Jean,

Taking a look into ##class(%Library.PosixTime)  you see that you shouldn't be concerned on efficiency
It's pretty obvious that the implementation is missing a selectable precision.
so

  • set stripped = $P(str,".",1)

Is similar effective as 

  • set stripped = $E(str,1,19) 

It's not perfect but will be correct and lasting for almost the next 8000 years 😉

Thanks all for the feedback and interesting code examples. Although it's twice as slow as the approach as @Julius.Kavay's clever numbers-only approach, I'm going with the string manipulation approach after all. I find it easier to document and therefore easier for an ObjectScript newby to understand. (Newby asks: "What do all those numbers mean? ☺)

/// Round the supplied PosixTime to whole seconds (strip microseconds)
ClassMethod RoundPosixToSeconds(posix As %Library.PosixTime) As %Library.PosixTime
{

    // Get the String representation of the posix time
    set str = ##class(%Library.PosixTime).LogicalToTimeStamp(posix)

    // Strip the microseconds value and the decimal point
    set stripped = $E(str,1,19)
    
    // Reconstruct the PosixTime object from the stripped String representation
    set newposix = ##class(%Library.PosixTime).TimeStampToLogical(stripped)
    quit newposix
}

NOTE: That last comment was generated by Tabnine VS Code extension. Needs an edit. 

I also appreciate the "timing" code that Julius provided. Here are the stats (after I ended up using $E instead of $P. (Thank you @Robert Cemper !)

CRMBI>set posix = 1154669852181849976
CRMBI>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(CRMBI.JSONSynced).RoundPosixToSeconds(posix) } w $zh-t
1.969733
CRMBI>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(CRMBI.JSONSynced).RoundPosixToSeconds(posix) } w $zh-t
2.025097
CRMBI>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(CRMBI.JSONSynced).RoundPosixToSeconds(posix) } w $zh-t
1.975352
CRMBI>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(CRMBI.JSONSynced).PosixToTimeStamp(posix) } w $zh-t
1.057825
CRMBI>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(CRMBI.JSONSynced).PosixToTimeStamp(posix) } w $zh-t
.92929
CRMBI>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(CRMBI.JSONSynced).PosixToTimeStamp(posix) } w $zh-t
.9343
CRMBI>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(CRMBI.JSONSynced).PosixToTimeStamp(posix) } w $zh-t
.941494
CRMBI>


Thank you all again