timestamp to milliseconds conversion around midnight getting messed up - perl

I am using following function to convert timestamp in format (e.g.) 02:49:02.506 to milliseconds in perl.
sub to_millis {
my( $hours, $minutes, $seconds, $millis) = split /:/, $_[0];
$millis += 1000 * $seconds;
$millis += 1000 * 60 * $minutes;
$millis += 1000 * 60 * 60 * $hours;
return $millis;
}
I am then using the milliseconds generated from above routine to calculate the time difference between two timestamps in milliseconds. This works fine all day but gets messed up around midnight, when the timestamp changes to 00:00:00.000. So any logs generated for 1 hr (between 12am to 1am) gets me values in negative for the timestamp difference. Since my timestamp doesn't have a date in it, how do I fix this problem? I am trying to do this on a mobile device, which doesn't have many perl modules installed. So I don't have the liberty of using all the perl modules available.

If you know the ordering of your two timestamps, and if you know that they're no more than 24 hours apart, if you get a negative difference add 24 hours (86,400,000 milliseconds).
If you don't have that information, then you won't be able to distinguish between a 2-minute span and a span of 24 hours and 2 minutes.

I assume that your timestamps will never be more than 23 hours 59 minutes apart?
Let's take two time stamps A and B. I am assuming that A happens before B.
Normally, if A is less than B, I know I can get my time by subtracting A from B. However, in this case, A is bigger than B. I now have to assume that I've wrapped around midnight. What do I do?
I know that the difference between A and B is A going to midnight, PLUS B.
For example, A is 11:58:30 and B is 00:02:00
I know that A will be 90 seconds before midnight, and B will add another 120 seconds to that time. Thus, the total difference will be 90 + 120 = 210 seconds.
Using your routine:
my $midnight = to_millis( "23:59:00:000" ); # Need the time at midnight
my $a_time = to_millis( $a_timestamp );
my $b_time = to_millis( $b_timestamp );
my $time_diff;
if ( $a_time < $b_time ) { # Normal timestamp issue
$time_diff = $b_time - $a_time;
}
else { # We wrapped around midnight!
my $first_part = $midnight - $a_time; # Time from A to midnight
$time_diff = $first_part + $b_time # We add the time from midnite to B
}

You have two timestamps, A and B. If B is always conceptually "after" A but the interval from A to B could cross a date boundary, then do
if (B < A) B+=86400000
and then do the subtraction. Or equivalently
diff = B - A
if (diff < 0) diff+=86400000
If, however you are not guaranteed that B will always be "after" A, you have to decide what is the acceptable range of positive and negative values for the difference. If it's more than half a day you're out of luck, there's no way to solve the problem as you cannot tell if a negative interval represents a real negative interval or a positive one that happened to cross a day boundary.

To handle the wrap around at midnight:
$elapsed_ms = $t2_ms - $t1_ms;
if ($elapsed_ms < 0) $elapsed_ms += (24 * 60 * 60 * 1000);

Related

How to calculate the next minute and next 5 minute intevals given a ZonedDateTime

I have a instance of a ZonedDatetime.
ZonedDateTime.now(ZoneId.of("America/New_York"))
I basically need a function that will take an instance of a ZonedDateTime and return the next 1 minute and 5 minute values.
So if the current time is:
2021-10-24T19:46:10.649817
The next minute will be 19:47:00 and the next 5 minute will be 19:50:00
The next 5 minute interval is always like:
1:00
1:05
1:10
1:15
1:20
1:25
...
1:50
1:55
2:00
i.e. the next 5 minute interval is not based on exactly 5 minutes from now, but rather the next 5 minutes based on starting from the beginning of the hour. Same goes for the next 1 minute interval in the future.
def nextIntervals(zdt: ZonedDateTime): (ZonedDateTime, ZonedDateTime) = {
???
}
It is fairly simple to do so without hardcoding the values. Unfortunately I'm not familiar with scala so I'll give you some pseudo code, I believe you'll be able to easily translate it.
nextIntervals(zdt) {
timestamp = zdt.toUnixTimestamp();
return [
new ZonedDateTime(timestamp + (60 - timestamp % 60)),
new ZonedDateTime(timestamp + (300 - timestamp % 300))
]
}
The above code assumes that ZonedDateTime can be instantiated by giving it a unix timestamp, measured in seconds. And also that it can be converted to a unix timestamp.
The idea is pretty simple: the remainder of the modulus will be the time that has elapsed since the last required period (in your case 1 minute or 5 minutes). Take that away from the period itself and you have the time that's left until the next period. Add that to the current time and you have the exact datetime.
Edit:
Here's a working javascript example
function nextIntervals(date) {
let t = date.getTime();
return [
60e3,
300e3,
].map(i => new Date(t + i - t % i));
}
console.log(nextIntervals(new Date));
You can use the following functions to meet your requirements:
ZonedDateTime#plusMinutes
ZonedDateTime#minusMinutes
ZonedDateTime#truncatedTo
Demo:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));
ZonedDateTime nextMinute = now.plusMinutes(1).truncatedTo(ChronoUnit.MINUTES);
ZonedDateTime nextMultipleOfFiveMin = now.truncatedTo(ChronoUnit.MINUTES)
.minusMinutes(now.getMinute() % 5)
.plusMinutes(5);
System.out.println(now);
System.out.println(nextMinute);
System.out.println(nextMultipleOfFiveMin);
}
}
Output from a sample run:
2021-10-25T16:59:22.662943-04:00[America/New_York]
2021-10-25T17:00-04:00[America/New_York]
2021-10-25T17:00-04:00[America/New_York]
Output from another sample run after a while:
2021-10-25T17:05:09.596952-04:00[America/New_York]
2021-10-25T17:06-04:00[America/New_York]
2021-10-25T17:10-04:00[America/New_York]
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time. Check this answer and this answer to learn how to use java.time API with JDBC.
Note: The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time.
We do need a little bit of hand-coded math to handle the 5-minute interval case. Excuse my Java syntax.
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println("Now: " + now);
// Truncate to the previous 5 minutes
ZonedDateTime zdt = now.truncatedTo(ChronoUnit.MINUTES);
zdt = zdt.withMinute(zdt.getMinute() / 5 * 5);
for (int i = 0; i <= 12; i++) {
zdt = zdt.plusMinutes(5);
System.out.println(zdt);
}
Example output:
Now: 2021-10-25T15:23:31.357567-04:00[America/New_York]
2021-10-25T15:25-04:00[America/New_York]
2021-10-25T15:30-04:00[America/New_York]
2021-10-25T15:35-04:00[America/New_York]
2021-10-25T15:40-04:00[America/New_York]
2021-10-25T15:45-04:00[America/New_York]
2021-10-25T15:50-04:00[America/New_York]
2021-10-25T15:55-04:00[America/New_York]
2021-10-25T16:00-04:00[America/New_York]
2021-10-25T16:05-04:00[America/New_York]
2021-10-25T16:10-04:00[America/New_York]
2021-10-25T16:15-04:00[America/New_York]
2021-10-25T16:20-04:00[America/New_York]
2021-10-25T16:25-04:00[America/New_York]
The trick to truncate to a whole multiple of 5 minutes is to divide by 5, obtain a whole number and discard any remainder, and multiply by 5 again.
The 1-minute interval is similar, only a bit simpler: we don’t need to do any math ourselves, java.time takes care of it all.

Pine scripting: how to find the price X days ago

In Pine Script, how do I find the price based on a certain number of days ago? I've tried something like this...
// Find the price 90 days ago
target = time - 90 * 60 * 60 * 24 * 1000
valuewhen(time < target, close, 1)
...however time < target never seems to return true – presumably because the current bar's time cannot also be in the past at the same time. Perhaps valuewhen() wasn't designed to be used with dynamic values that change on every bar?
Do I need to use a loop instead, and scan through every past bar until I find the date I'm looking for?
Perhaps there's a better way, but the workaround I'm using currently using is a function with a for loop, scanning backwards until the appropriate date is found. Here is my function:
priceXDaysAgo(numDays) =>
targetTimestamp = time - numDays*60*60*24*1000
// Declare a result variable with a "void" value
float result = if false
1
// We'll scan backwards through the preceding bars to find the first bar
// earlier than X days ago (it might be a little greater than X days if
// there was a break in trading: weekend, public holiday, etc.)
for i = 1 to 1000
if time[i] < targetTimestamp
result := close[i]
break
result
You can then call the function anywhere in your script:
priceXDaysAgo(90)

Convert unix time to month number?

Using os.time how can I get how many months have passed since the unix epoch (Unix Timestamp)
I just need it for a month ID, so any kind of number would be fine, as long as it changes every month, and it can be reversed to get the actual month.
local function GetMonth(seconds)
local dayduration,year = 3600*24
local days={31,0,31,30,31,30,31,31,30,31,30,31}
for i=1970,10000 do -- For some reason too lazy to use while
local yeardays = i%4 == 0 and i%100 ~= 0 and 366 or 365
local yearduration = dayduration * yeardays
if yearduration < seconds then
seconds = seconds - yearduration
else
year = i break
end
end
days[2]=(year%4==0) and 29 or 28
seconds = seconds%(365*24*3600)
for i=1,12 do
if seconds>days[i]*dayduration then
seconds=seconds-days[i]*dayduration
else
return --i + year*12 <-- If you want a unique ID
end
end
end
Currently, it'll give the number 2, since it's February. If you uncomment the code at the end for the unique ID, you'll get 554 instead, meaning we're currently at the 554th month since the epoch.
As Jean-Baptiste Yunès said in his answer's comments, I'm not sure if your sentence:
NOTE: This is for Lua, but I'm unable to use os.date
meant you have no os.date, or that you don't know how to use it. You have an answer for both cases, you can use the one you need.
This may do the trick:
print (os.date("*t",os.time())["month"])
os.time() gives you the current date as a number. os.date("*t",...) converts it into a table in which the month equals to the number of the month corresponding to the date.

subtracting one from another in matlab

My time comes back from a database query as following:
kdbstrbegtime =
09:15:00
kdbstrendtime =
15:00:00
or rather this is what it looks like in the command window.
I want to create a matrix with the number of rows equal to the number of seconds between the two timestamps. Are there time funcitons that make this easily possible?
Use datenum to convert both timestamps into serial numbers, and then subtract them to get the amount of seconds:
secs = fix((datenum(kdbstrendtime) - datenum(kdbstrbegtime)) * 86400)
Since the serial number is measured in days, the result should be multiplied by 86400 ( the number of seconds in one day). Then you can create a matrix with the number of rows equal to secs, e.g:
A = zeros(secs, 1)
I chose the number of columns to be 1, but this can be modified, of course.
First you have to convert kdbstrendtime and kdbstrbegtime to char by datestr command, then:
time = datenum(kdbstrendtime )-datenum(kdbstrbegtime )
t = datestr(time,'HH:MM:SS')

Difference in minutes between 2 dates and times?

I need to compute time difference in minutes with four input parameters, DATE_FROM, DATE_TO, TIME_FROM, TIME_TO. And one output parameter DIFF_TIME. I have created a function module, I need to write a formula which computes the time diff in minutes.
Any help would be great!
Thanks,
Sai.
Use CL_ABAP_TSTMP=>TD_SUBTRACT to get the number of seconds between two date/time pairs.
(then, to get the number of minutes, divide the number of seconds by 60).
Example:
DATA(today_date) = CONV d( '20190704' ).
DATA(today_time) = CONV t( '000010' ).
DATA(yesterday_date) = CONV d( '20190703' ).
DATA(yesterday_time) = CONV t( '235950' ).
cl_abap_tstmp=>td_subtract(
EXPORTING
date1 = today_date
time1 = today_time
date2 = yesterday_date
time2 = yesterday_time
IMPORTING
res_secs = DATA(diff) ).
ASSERT diff = 20. " verify expectation or short dump
If the values are guaranteed to be in the same time zone, it's easy enough that you don't need any special function module or utility method. Read this, then get the difference of the dates and multiply that by 24 * 60 and get the difference of the times (which is in seconds) and divide that by 60. Sum it up and there you are.