Groovy time durations - time

Hi I'm trying to calculate the difference (duration) between two times in Groovy. e.g.
start = "2010-10-07T22:15:33.110+01:00"
stop = "2010-10-07T22:19:52.356+01:00"
Ideally I would like the get the duration returned in Hours, Minutes, Seconds, Milliseconds.
Can anybody please help. I've tried to use Groovy's duration classes but have not been able to make any progress.
Thanks for your assistance.

If you just want to find the difference between two times you create yourself (for instance to see how long something takes to execute) you could use:
import groovy.time.*
def timeStart = new Date()
// Some code you want to time
def timeStop = new Date()
TimeDuration duration = TimeCategory.minus(timeStop, timeStart)
println duration
If you specifically need to work with the dates as supplied as string above. Try this, first the format of them is a bit odd, in particular the +01:00, which is the timezone, I would expect it to be +0100 for format to work. You could just remove the timezone I just did a replace.
import groovy.time.*
def start = Date.parse("yyy-MM-dd'T'HH:mm:ss.SSSZ","2010-10-07T22:15:33.110+01:00".replace("+01:00","+0100"))
println start
def end = Date.parse("yyy-MM-dd'T'HH:mm:ss.SSSZ","2010-10-07T22:19:52.356+01:00".replace("+01:00","+0100"))
println end
TimeDuration duration = TimeCategory.minus(end, start)
println duration
Outputs
Thu Oct 07 15:15:33 MDT 2010
Thu Oct 07 15:19:52 MDT 2010
4 minutes, 19.246 seconds

I would do something like that
def elapsedTime(Closure closure){
def timeStart = new Date()
closure()
def timeStop = new Date()
TimeCategory.minus(timeStop, timeStart)
}
an then
TimeDuration timeDuration = elapsedTime { /*code you want to time*/ }

Using the java.time.* packages
Suggested by groovy linters with the message 'Do not use java.util.Date. Prefer the classes in the java.time. packages'*
import java.time.Instant
import java.time.temporal.ChronoUnit
long elapsedTime(Closure closure) {
Instant timeStart = Instant.now()
closure()
Instant timeStop = Instant.now()
return ChronoUnit.MILLIS.between(timeStart, timeStop)
}
println elapsedInMillis = elapsedTime {
// code you want to time, e.g.:
sleep 456
}
More info: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html

I had the same question and I used what Demian suggested in his answer, except that I needed it to be generic and to work with any values of start or stop, hence I'm sharing this improvement of Demian's answer for future reference.
It just uses the OP variables, with a generic replacement using a regex, so as to keep the value of the time-zone offset
Note that groovy.time.TimeDuration is not serializable, and thus will mess up with the jenkins' CPS-groovy and throw java.io.NotSerializableException.
import groovy.time.*
def start = "2010-10-07T22:15:33.110+01:00"
def stop = "2010-10-07T22:19:52.356+01:00"
def format = "yyy-MM-dd'T'HH:mm:ss.SSSZ"
start = Date.parse(format , start.replaceAll(/([+\-])(\d\d):(\d\d)/, /$1$2$3/))
println start
stop = Date.parse(format , stop.replaceAll(/([+\-])(\d\d):(\d\d)/, /$1$2$3/))
println stop
TimeDuration duration = TimeCategory.minus(stop, start)
println duration

Related

Issues with System.currentTimeMillis() on TicWatch / Emulator / Samsung Galaxy Watch 4

I get different answers depending on which watch the following code is run on
val prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE)
val appClosedTime = prefs.getLong(KEY_APP_CLOSE_TIME, System.currentTimeMillis()) // default to now
val elapsedTime = System.currentTimeMillis() - appClosedTime // in milliseconds
The above code gives the right answer on both the Samsung Galaxy Watch 4 (Wear OS 3) and a Google Emulator (Wear Round API 30)
Unfortunately when the same code is run on the TicWatch (Wear OS 2) the elapsedTime includes the local time offset from UTC.
The following code can be used to adjust for the difference
val prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE)
val appClosedTime = prefs.getLong(KEY_APP_CLOSE_TIME, System.currentTimeMillis()) // default to now
val currentSystemTime = GregorianCalendar()
val localTimeOffsetFromUTC = currentSystemTime.timeZone.getOffset(appClosedTime)
val elapsedTime = System.currentTimeMillis() - (appClosedTime-localTimeOffsetFromUTC)
My code currently checks which watch I am using and makes the adjustment however this 'hack' is clearly impractical since it must be tested on each and every watch!
I am hoping someone can suggest something I am missing / overlooking / doing wrong ?
Code snippets and further information
System.currentTimeMillis() says it returns the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
appCloseTime is stored in onStop()
val editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit()
editor.putLong(KEY_APP_CLOSE_TIME, System.currentTimeMillis())
editor.apply()

How to convert Time in JMeter in 24 Hr format, while using shiftTime function to convert IST to UTC format?

Actually I'm trying to to shift the time, the application I'm working on is in UTC and I'm working in IST.
I've used both BEAN Shell pre processor and shiftTime function
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
int AddSeconds= 00; //this variable needs to be customized as per your need
int AddMinutes= 392; //this variable needs to be customized as per your need
int AddHours= 00; //this variable needs to be customized as per your need
Date now = new Date();
Calendar c = Calendar.getInstance();
c.setTime(now);
c.add(Calendar.SECOND, AddSeconds);
c.add(Calendar.MINUTE, AddMinutes);
c.add(Calendar.HOUR, AddHours);
Date NewTime = c.getTime();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String mytime = df.format(NewTime);
vars.put("NewTime",mytime);
Shift Time :
"${__timeShift(yyyy-MM-dd'T'HH:mm:ss.SSS'Z',,PT393M,,)}"
Bun when I run the HTTP Request in Jmeter the time format is coming in 12Hrs only instead of 24 Hr
Also Time shift is taking in weird manner, I've tried all options from Stackoverflow from last 2 days and unable to achieve my task to convert IST to UTC.
This is what I'm using in Jmeter Post body
enter image description here
And this is what I'm getting as result
enter image description here
Time formats are getting totally mismatched here, can someone please help me to convert IST to UTC correctly while playing with these time formats and functions.
I don't think you can use __timeShift() function for getting the date in the different timezone, it will return you the current (default) one
So if you need to add 392 minutes to the current time in the time zone different from yours - you will have to go for __groovy() function and use TimeCategory class
Example code:
${__groovy(def now = new Date(); use(groovy.time.TimeCategory) { def nowPlusOneYear = now + 392.minute; return nowPlusOneYear.format("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"\,TimeZone.getTimeZone('IST')) },)}
Demo:
If you need to get the time in UTC just change IST to UTC
${__groovy(def now = new Date(); use(groovy.time.TimeCategory) { def nowPlusOneYear = now + 392.minute; return nowPlusOneYear.format("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"\,TimeZone.getTimeZone('UTC')) },)}
More information: Creating and Testing Dates in JMeter - Learn How
Also be informed that since JMeter 3.1 you're supposed to be using JSR223 Test Elements and Groovy language for scripting
Just adding one more way to do this via bean shell preprocessor and it worked for me pretty well.
Here is the code to use... here -325 minutes is the difference between IST and UTC
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
int AddSeconds= 00; //this variable needs to be customized as per your need
int AddMinutes= -325; //this variable needs to be customized as per your need
int AddHours= 00; //this variable needs to be customized as per your need
Date now = new Date();
Calendar c = Calendar.getInstance();
c.setTime(now);
c.add(Calendar.SECOND, AddSeconds);
c.add(Calendar.MINUTE, AddMinutes);
c.add(Calendar.HOUR, AddHours);
Date NewTime = c.getTime();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String mytime = df.format(NewTime);
vars.put("NewTime",mytime);
// NewTime is your jmeter variable

Handling offset naive object

I am trying to find the time until the next day according to IST. I am using pytz. I am not getting why "tomorrow" is offset naive while tomorrow is defined using offset aware constants.
I've tried printing stuff like print tomorrow_date - now , but that gives 0 and i do not know how is that happening.
from datetime import datetime,timedelta
from pytz import timezone
ist = timezone('Asia/Kolkata')
def get_until_tomorrow():
now = datetime.now(ist)
#today = date.today()
tomorrow_date = now + timedelta(days=1)
tomorrow = datetime.combine(tomorrow_date,time=time(00,00))
seconds_left = tomorrow - now
return seconds_left.seconds
print(get_until_tomorrow())
I am getting the error that I cannot subtract an offset naive and an offset aware object. now is an offset aware object because i set it so directly, but tomorrow is, according to it, an offset naive variable. How is this possible when i have used only offset aware variables to define tomorrow?
Looks like you have to make it offset aware by using localise. See if this helps.
from datetime import datetime,timedelta, time
from pytz import timezone
ist = timezone('Asia/Kolkata')
def get_until_tomorrow():
now = datetime.now(ist)
tomorrow_date = now + timedelta(days=1)
tomorrow = datetime.combine(tomorrow_date,time=time(00,00))
tomorrow = ist.localize(tomorrow)
seconds_left = tomorrow - now
return seconds_left.seconds
print(get_until_tomorrow())

Set current time in init ELM 0.19

I get input JSON data from JS. This is a simple object, among which there is a date in the format "DD.MM.YYYY" - just a string.
If there is no dateStart in the object, I have to replace it with the current date (in withDefault).
paramsDecoder : Decode.Decoder Params
paramsDecoer =
Decode.succeed Params
|> Decode.andMap (Decode.field "dateStart" (Decode.string) |> (Decode.withDefault) "")
|> Decode.andMap (Decode.field "dateEnd" (Decode.string) |> (Decode.withDefault) "")
|> Decode.andMap (Decode.field "country" (Decode.string) |> (Decode.withDefault) "spain")
How can I do this in ELM?
Timezone is not important and is always equal to the same region.
I found an example of Time.now Time.zone usage,
but there time is getting in Update and its too late.
I solved this in two parts:
Part 1
Send the current time in to Elm when it initializes, using flags:
Elm.Main.init({flags: Date.now()});
And put it in your model:
import Time exposing (Posix, millisToPosix)
type alias Model = { now : Time.Posix, ... }
init : Int -> (Model, Cmd Msg)
init time = (Model (millisToPosix time), Cmd.none)
For your use case, you can then use withDefault model.now.
Part 2
The solution in Part 1 will only set now to the time when the page is loaded.
If you want to keep an up to date time you can use Time.every to update your model:
import Time exposing (Posix, millisToPosix, every)
timeOutCheck : Sub Msg
timeOutCheck = Time.every 250 UpdateTimeNow
type Msg = UpdateTimeNow Posix | ...
update msg model = case msg of
UpdateTimeNow time = { model | now = time }
...
This will ensure now is never more than 250 ms behind the current time. You can change 250 to suit your need.

Check that Instant now happens during the java.time.Period / Duration

My intent is to set a condition to true only during a period.
The java.time.* API looked what I need.
import java.time.Period
import java.time.LocalTime
import java.time.Instant
import java.time.Duration
// java.time.Period
LocalTime start = LocalTime.of(1, 20, 25, 1024);
LocalTime end = LocalTime.of(3, 22, 27, 1544);
Period period = Period.between(startDate, endDate);
// java.time.duration
Instant start = Instant.parse("2017-10-03T10:15:30.00Z")
Instant end = Instant.parse("2019-10-03T10:16:30.00Z")
Duration duration = Duration.between(start, end)
Instant now = Instant.now();
How to check that now is happening during the defined Period / Duration ?
I see no direct API.
Edit :
I found a way with java.time.Instant
// now, start and end are defined above
// if now is between start and end
if (now.isAfter(start) && now.isBefore(end)){
}
You are mistaken about what Period and Duration are.
They are distances (subtract beginning from ending). Period between 01/03/2018 and 01/10/2018 is exactly the same as in between 05/04/1990 and 05/11/1990, same thing for Duration. So that means nothing to ask something like "is 3rd january, 2018 in 3 months?"
First: a simple solution:
LocalTime start = LocalTime.of(1, 20, 25, 1024);
LocalTime end = LocalTime.of(3, 22, 27, 1544);
LocalTime now = LocalTime.now()
boolean nowIsInTimeWindow = !(now.isBefore(start) || now.isAfter(end));
The same pattern works with LocalDate and LocalDateTime.
Second: additional thoughts on your original post:
now will never happen "during" period or duration. Both are just amounts of time, like "two days" or "five minutes". They don't contain information about start or end.
I'd suggest to not mix Instant and LocalDate but to use LocalTime instead of Instant. Thus you're consistent with regard to timezone: The Local... types are by definition timezone agnostic.

Resources