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

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()

Related

Get Stage View Times for Current Build

Is it possible to get the stage view time values programatically?
I would like to print within the console the stage times for all the stages including the stage titles.
Something like:
Build Code: 19s
Unit Tests: 7s
Integration Tests: 17s
Looking at the plugin code I can see how it's rendered through the formatter, but I can't figure out how I could access those values through a Jenkinsfile.
In the source code it looks like millisecond time is being used. I can convert that easily to better human readable time.
/**
* Calculate how long something took from start to end
* #param start Start time in milliseconds
* #param end End Time in milliseconds
* #return Duration as String from start to end
*/
def calculateDuration(start, end) {
long elapsedTime = end - start
Long second = (elapsedTime / 1000).longValue() % 60;
Long minute = (elapsedTime / (1000 * 60)).longValue() % 60;
Long hour = (elapsedTime / (1000 * 60 * 60)).longValue() % 24;
Long remainderMillis = elapsedTime % 1000
return "${hour}h ${minute}m ${second}s ${remainderMillis}ms"
}
So this isn't going to be the super easy solution you're looking for, but I didn't know how to do this either and wanted to try.
Basically I'm writing simple HTML to a file at the OS level, and at the end publishing it via the Rich Text Publisher plugin. It then displays on the build page.
I'm not sure how to properly format the duration into hh:mm:ss
def logit(logMessage) {
logFile.append(logMessage + "\n")
}
def calculateDuration(start, end) {
long elapsedTime = end - start
Long second = (elapsedTime / 1000).longValue() % 60;
Long minute = (elapsedTime / (1000 * 60)).longValue() % 60;
Long hour = (elapsedTime / (1000 * 60 * 60)).longValue() % 24;
Long remainderMillis = elapsedTime % 1000
return "${hour}h ${minute}m ${second}s ${remainderMillis}ms"
}
node () {
stage('Create logfile') {
sh "rm -f /tmp/log.html"
logFile = new File("/tmp/log.html")
logit("<html>")
logit(" <body>")
}
stage('Time this stage') {
start = System.currentTimeMillis()
logit("Start time " + start + "<br>")
sleep(3)
end = System.currentTimeMillis()
logit("End time " + end + "<br>")
dur = calculateDuration(start, end)
println "Duration: " + dur
logit("Duration: " + dur + "<br>")
}
stage('Publish') {
logit(" </body>")
logit("</html>")
rtp (nullAction: '1', stableText: '${FILE:/tmp/log.html}')
}
}
Ironically, years later I have discovered a better solution that gives me exactly what I needed, which was the time by stage.
Depending on the type of Jenkins job, Freeestyle or Multibranch you can look at the exposed Jenkins API endpoints to get the information.
Freestyle Endpoint: env.BUILD_URL/api/json?pretty=true
Multibranch endpoint: env.BUILD_URL/wfapi/describe
It's a JSON response, so it's easy to parse and store by using readJSON Jenkins DSL.
Below you can see an example response for a freestyle job. Sorry for the blackout but didn't want to expose corporate dir structures.

Observable Interval without drift

I am using Observable.interval to schedule code execuiton at specified times:
let obs = Observable.interval(50).subscribe(()=>{
console.log(this.currentFrame+" "+new Date().getTime());
this.currentFrame++
});
This is the output. As you can see, after 6 iterations I already have a 10ms drift. How can I use Observable.interval, but also specify that it needs to recalculate next iteration based on the current drift?
0 1513972329849
1 1513972329901
2 1513972329952
3 1513972330004
4 1513972330057
5 1513972330110
Until #cartant's fix gets repulled, you could use expand and create the behavior yourself. Assuming delay will always drift forward, try the following:
function correcting_interval(interval) {
const start_time = new Date().getTime();
return Observable.of(-1)
.expand(v => Observable.of(v + 1).delay(interval - (new Date().getTime() - start_time) % interval))
.skip(1);
}

boost log text_file_backend performance

I am using boost log and I choose the text_file_backend, but I got bad performance. No matter sync or async, the boost log has a low performance. About in 6 seconds, it wrote 30M data to log file.
Follow is my code snippet, anyone can help me?
typedef boost::log::sinks::asynchronous_sink<
boost::log::sinks::text_file_backend> TextSink;
boost::log::sources::severity_logger_mt<LogSev> logger_;
boost::shared_ptr<TextSink> report_sink_;
// initialize report_sink
boost::shared_ptr<sinks::text_file_backend> report_backend =
boost::make_shared<sinks::text_file_backend>(
keywords::file_name = target + "/" + file_name
+ ".report.log.%Y_%m_%d.%N",
keywords::rotation_size = file_size, keywords::time_based_rotation =
sinks::file::rotation_at_time_point(0, 0, 0),
keywords::auto_flush = false);
boost::shared_ptr<sinks::file::collector> report_collector = CreateCollector(
target, max_use_size / 2, min_free_size);
report_backend->set_file_collector(report_collector);
report_backend->scan_for_files();
// add sink: report_sink
report_sink_ = boost::make_shared<TextSink>(report_backend);
report_sink_->set_formatter(
expr::format("[%1%]" + sep + "[%2%]" + sep + "[%3%]" + sep + "%4%")
% expr::format_date_time<boost::posix_time::ptime>(
"TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
% expr::attr<LogSev>("Severity")
% expr::attr<attrs::current_thread_id::value_type>("ThreadID")
% expr::message);
report_sink_->set_filter(expr::attr<LogSev>("Severity") >= report);
logging::core::get()->add_sink(report_sink_);
logging::add_common_attributes();
BOOST_LOG_SEV(logger_, info) << "blabal...";
I think one performance issue about your implementation is about Timestamp. It needs a system-call to find Time. I encountered the same problem. So I turned to use date library. It returns UTC time very fast. Also check first answer of this question, However if you want Timestamp based on timezone, date library is slow. you should better define your timezone and add to UTC.
see the example:
#include "date.h"
#define MY_TIME std::chrono::hours(4) + std::chrono::minutes(30)
string timestamp = date::format("%F %T", std::chrono::system_clock::now() +
MY_TIME);

Adding current time played to total time played

I have a database with the total played game time in seconds. I want to fetch these seconds from the database, add the current session play time in seconds and then update the database.
This should happen every 5 seconds. I have done this, but because I do currentSession + totalTimePlayedDB it keeps adding the full duration of my current session over and over... Any ideas?
local currentPlayTime = player:TimeConnected()
print(math.Round(currentPlayTime))
local playerValues = MySQLite.queryValue([[SELECT time FROM chiz_time WHERE sid=']].. player:SteamID() ..[[']], function(time)
if time == "" then
time = math.Round(currentPlayTime)
else
time = math.Round(time + time - currentPlayTime )
end
MySQLite.query([[UPDATE chiz_time SET time = ']].. time ..[[' WHERE sid=']].. player:SteamID() ..[[']])
end)
I do currentSession + totalTimePlayedDB it keeps adding the full duration of my current
You just need to compute the delta from your last save time.
In your init code somewhere:
lastSaveTime = 0
In your save routine:
totalTimePlayedDB = totalTimePlayedDB + currentSession - lastSaveTime
if (totalTimePlayedDB is written to the database successfully) then
lastSaveTime = currentSession
end

Groovy time durations

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

Resources