Int96Value to Date string - scala

When reading a parquet file (using Scala) I read the timestamp field back as:
Int96Value{Binary{12 constant bytes, [0, 44, 84, 119, 54, 49, 0, 0, -62, -127, 37, 0]}}
How can I convert it to a date string?

I did some research for you. The Int96 format is quite specific a seems to be deprecated.
Here is a discussion about converting Int96 to Date.
Based on this, I created following piece of code:
def main(args: Array[String]): Unit = {
import java.util.Date
import org.apache.parquet.example.data.simple.{Int96Value, NanoTime}
import org.apache.parquet.io.api.Binary
val int96Value = new Int96Value(Binary.fromConstantByteArray(Array(0, 44, 84, 119, 54, 49, 0, 0, -62, -127, 37, 0)))
val nanoTime = NanoTime.fromInt96(int96Value)
val nanosecondsSinceUnixEpoch = (nanoTime.getJulianDay - 2440588) * (86400 * 1000 * 1000 * 1000) + nanoTime.getTimeOfDayNanos
val date = new Date(nanosecondsSinceUnixEpoch / (1000 * 1000))
println(date)
}
However, it prints Sun Sep 27 17:05:55 CEST 2093. I am not sure, if this is a date, that you expected.
Edit: using Instance as suggested:
val nanosInSecond = 1000 * 1000 * 1000;
val instant = Instant.ofEpochSecond(nanosecondsSinceUnixEpoch / nanosInSecond, nanosecondsSinceUnixEpoch % nanosInSecond)
println(instant) // prints 2093-09-27T15:05:55.933865216Z

java.time supports Julian days.
Credits to ygor for doing the research and finding out how to interpret the 12 bytes of your array.
byte[] int96Bytes = { 0, 44, 84, 119, 54, 49, 0, 0, -62, -127, 37, 0 };
// Find Julian day
int julianDay = 0;
int index = int96Bytes.length;
while (index > 8) {
index--;
julianDay <<= 8;
julianDay += int96Bytes[index] & 0xFF;
}
// Find nanos since midday (since Julian days start at midday)
long nanos = 0;
// Continue from the index we got to
while (index > 0) {
index--;
nanos <<= 8;
nanos += int96Bytes[index] & 0xFF;
}
LocalDateTime timestamp = LocalDate.MIN
.with(JulianFields.JULIAN_DAY, julianDay)
.atTime(LocalTime.NOON)
.plusNanos(nanos);
System.out.println("Timestamp: " + timestamp);
This prints:
Timestamp: 2017-10-24T03:01:50
I’m not happy about converting your byte array to an int and a long by hand, but I don’t know Parquet will enough to use the conversions that are probably available there. Use them if you can.
It doesn’t matter which LocalDate we use as starting point since we are changing it to the right Julian day anyway, so I picked LocalDate.MIN just to pick one.
The way I read the documentation, Julian days are always in the local time zone, that is, no time zone is understood, and they always start at midday (not midnight).
Link: Documentation of JulianFields in java.time

Related

How to convert time in seconds to 00:00:00 format in Flutter?

For example, if times is given as 1.05 seconds, we need to convert it as 00:01:05.
How can we achieve this in Flutter?
Also, if a time is given as duration in milliseconds, how do we convert it to the 00:00:00 format?
You just need some simple integer maths to separate the duration into the units you want and some string formatting to make sure that single-digit numbers get leading zeros.
String formatForVideo(Duration d) {
final millis = d.inMilliseconds;
if (millis >= 3600000) {
throw FormatException('too big to format');
}
final minutes = _pad2(d.inMinutes);
final seconds = _pad2(d.inSeconds % 60);
final cents = _pad2((millis % 1000) ~/ 10);
return '$minutes:$seconds.$cents';
}
String _pad2(int i) => i.toString().padLeft(2, '0');
Which gives expected results:
print(formatForVideo(Duration(minutes: 0, seconds: 1, milliseconds: 50))); // 00:01.05
print(formatForVideo(Duration(minutes: 9, seconds: 51, milliseconds: 50))); // 09:51.05
print(formatForVideo(Duration(minutes:60))); // exception
The output of this definition => 00:00:00
DateTime time = DateTime(1990, 1, 1, 0, 0, 0, 0, 0);
Then when you want to add a period to this time
time.add(const Duration(seconds: 100,milliseconds:200))
and for output =>
String timeString = DateFormat.Hms().format(time);
print(timeString);
Result =>> 00:01:40

Decode Ble data raw flutter

I'm developing a flutter app using the flutter_blue library to interface a BlueNRG-tile from STMicroelectronics. I'm receiving the the raw data from the desired caracteristics then i'm note able ble to convert them to string using the utf8.decode() function.
This is the received data as a list and the issue.
I/flutter (32277): Teste conversion : [121, 85, 0, 0, 209, 133, 1, 0, 5, 10, 237, 0, 0, 0]
E/flutter (32277): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: FormatException: Missing extension byte (at offset 11).
the code from the in the st board:
tBleStatus Environmental_Update(int32_t Press,int32_t Press2,uint16_t Hum, int16_t Temp,int16_t Temp2) {
uint8_t BuffPos = 0;
STORE_LE_16(buff, (getTimestamp()));
BuffPos = 2;
STORE_LE_32(buff + BuffPos, Press);
BuffPos += 4;
STORE_LE_16(buff + BuffPos, Hum);
BuffPos += 2;
STORE_LE_16(buff + BuffPos, Temp);
BuffPos += 2;
STORE_LE_16(buff + BuffPos, Temp2);
return aci_gatt_update_char_value(HWServW2STHandle, EnvironmentalCharHandle, 0, EnvironmentalCharSize, buff);
}
Environmental_Update(PressToSend,PressToSend2, HumToSend, TempToSend,TempToSend2);
Thank You.
You are not able to convert your RAW data to string because you are not sending it as string but in form of bytes.
Take your temperature for example:
You receive the temperature as int16_t, a 16-bit number storing values from –32768 to 32767. This number needs two bytes to be stored, that's why you used BuffPos += 2; and increased the position by 2 bytes.
You need to extract the values from your received array the same way, bytewise. Have a look at this example:
import 'dart:typed_data';
int fromBytesToInt16(int b1, int b0) {
final int8List = new Int8List(2)
..[1] = b1
..[0] = b0;
return ByteData.sublistView(int8List).getInt16(0);
}
void main() {
var received = [121, 85, 0, 0, 209, 133, 1, 0, 5, 10, 237, 0, 0, 0];
var temp = fromBytesToInt16(received[8], received[9]) / 100;
print('temperature: $temp');
}
The temperature was stored as a int16 at index 8 and 9 so I converted it the same way. This results in a temp value of 2565, which divided by 100 would give a pretty nice temperature of 25.65 degree

How to calculate time difference between two dates using LocalDateTime in Java 8?

There are numerous answers given but I am unable to find compatible with my situation. I need to find difference of 8 hours in time as well as on date change too. Like if time is greater then 8 hours then do not execute something .
Do we have any method which achieve the same in LocalDateTime in Java-8?
I have tried to use following but unable to achieve the same.
LocalDateTime fromDateTime = LocalDateTime.of(2017, 07, 07, 07, 00, 55);
LocalDateTime toDateTime = LocalDateTime.now();
LocalDateTime tempDateTime = LocalDateTime.from(fromDateTime);
long years = tempDateTime.until(toDateTime, ChronoUnit.YEARS);
tempDateTime = tempDateTime.plusYears(years);
long months = tempDateTime.until(toDateTime, ChronoUnit.MONTHS);
tempDateTime = tempDateTime.plusMonths(months);
long days = tempDateTime.until(toDateTime, ChronoUnit.DAYS);
tempDateTime = tempDateTime.plusDays(days);
long hours = tempDateTime.until(toDateTime, ChronoUnit.HOURS);
tempDateTime = tempDateTime.plusHours(hours);
long minutes = tempDateTime.until(toDateTime, ChronoUnit.MINUTES);
tempDateTime = tempDateTime.plusMinutes(minutes);
long seconds = tempDateTime.until(toDateTime, ChronoUnit.SECONDS);
System.out.println("" + java.time.Duration.between(tempDateTime, toDateTime).toHours());
System.out.println(years + " years "
+ months + " months "
+ days + " days "
+ hours + " hours "
+ minutes + " minutes "
+ seconds + " seconds.");
It is difficult to check on time and date separately.
Initially I coded it like but it does not looks correct:
return openBrat!=null
&& openBrat.until(LocalDateTime.now(), ChronoUnit.DAYS) == 0 &&
openBrat.until(LocalDateTime.now(), ChronoUnit.HOURS) >= 8
&& openBrat.until(LocalDateTime.now(), ChronoUnit.Minutes) >= 0;
Could anyone please suggest how to subtract like:
2017 07 06 23:30:00 - 2017 07 07 01:30:00 - Should return 2 hours.
The following prints 2, just like you'd expect.
LocalDateTime ldt1 = LocalDateTime.of(2017, 07, 06, 23, 30, 00);
LocalDateTime ldt2 = LocalDateTime.of(2017, 07, 07, 1, 30, 00);
System.out.println(Duration.between(ldt1, ldt2).toHours());
There is nothing wrong with your code. If you don't get the outcome you expect, you may need to check if your expectation is correct.
To do something when the difference is less than 8 hours, you can do something like this:
LocalDateTime ldt1 = LocalDateTime.of(2017, 07, 06, 23, 30, 00);
LocalDateTime ldt2 = LocalDateTime.of(2017, 07, 07, 1, 30, 00);
Duration d1 = Duration.between(ldt1, ldt2);
Duration d2 = Duration.ofHours(8);
if (d1.compareTo(d2) > 0) {
System.out.println("do nothing");
} else {
System.out.println("do something");
}
My understanding is that you want to get the difference between those 2 dates and "break" it in terms of how many hours, minutes and seconds this difference is.
You can use the Duration class as already explained. But the Duration calculates the difference in seconds and nanoseconds, so you'll have to do some math to get this amount of seconds in separate fields:
LocalDateTime d1 = LocalDateTime.of(2017, 7, 6, 23, 30, 0);
LocalDateTime d2 = LocalDateTime.of(2017, 7, 7, 7, 0, 55);
Duration duration = Duration.between(d1, d2);
// total seconds of difference (using Math.abs to avoid negative values)
long seconds = Math.abs(duration.getSeconds());
long hours = seconds / 3600;
seconds -= (hours * 3600);
long minutes = seconds / 60;
seconds -= (minutes * 60);
System.out.println(hours + " hours " + minutes + " minutes " + seconds + " seconds");
In Java 9 and later, you can call the new Duration::to…Part methods to get number of days, hours, minutes, or seconds rather than calculate the numbers yourself.
The output will be:
7 hours 30 minutes 55 seconds
And the variables hours, minutes and seconds will have the respective values of 7, 30 and 55. If you also want the nanoseconds, just call duration.getNano() to get the respective value (in the example above, it's 0).
If I test with different values:
LocalDateTime d1 = LocalDateTime.of(2017, 7, 6, 23, 30, 0);
LocalDateTime d2 = LocalDateTime.of(2017, 7, 7, 1, 30, 0);
The result will be:
2 hours 0 minutes 0 seconds
If you just want the difference in hours, you can use:
ChronoUnit.HOURS.between(d1, d2);
You can optionally use Math.abs to avoid negative values.
This will return the difference in hours, ignoring the remaining minutes and seconds: in the first example (d2 = LocalDateTime.of(2017, 7, 7, 7, 0, 55)) it will return 7 and in the second example (d2 = LocalDateTime.of(2017, 7, 7, 1, 30, 0)) it will return 2.

In a YYyyMMDD format date where YY may or may not be correct, how would you correct YY without hardcoding?

I'm not sure if this is the right place for this question but I'll ask anyway.
We get data from a source we can't control. Those data contains dates in YYyyMMDD. The thing is, the data source has a bug in their system which makes the YY part of the date randomly incorrect so we need to make a workaround for it.
So I thought I'll just append the last six digits of the date to today's YY
substr($date_today,0,2).substr($date,-6)
But the years in those data are not just for this year, it's also for future years.
so let's say today is 2091-09-07 and this system is still running and then we get a date that is 2102-08-06. Then we also get a date with an incorrect year like 2302-09-04. How should I correct it? What sort of coding solution should I do to workaround these errors?
I'm using Perl btw.
If you assume that the years from your data source aren't more than 50 years in the past or future, the following subroutine can be used to guess the correct year given the current year and the last two digits of the year from your data source:
sub guess_year {
my ($cur_year, $yy) = #_;
my $cur_yy = $cur_year % 100;
my $YY = $cur_year - $cur_yy;
if ($cur_yy < 50) {
# Previous century.
if ($yy >= $cur_yy + 50) { $YY -= 100; }
}
else {
# Next century.
if ($yy < $cur_yy - 50) { $YY += 100; }
}
return $YY + $yy;
}
Here are a couple of test cases:
sub test {
my ($cur_year, $yy) = #_;
my $guess = guess_year($cur_year, $yy);
print("cur_year: $cur_year, yy: $yy, guess: $guess\n");
}
test(2016, 15);
test(2016, 17);
test(2016, 60);
test(2016, 70);
test(2080, 79);
test(2080, 81);
test(2080, 10);
test(2080, 40);
And the results:
cur_year: 2016, yy: 15, guess: 2015
cur_year: 2016, yy: 17, guess: 2017
cur_year: 2016, yy: 60, guess: 2060
cur_year: 2016, yy: 70, guess: 1970
cur_year: 2080, yy: 79, guess: 2079
cur_year: 2080, yy: 81, guess: 2081
cur_year: 2080, yy: 10, guess: 2110
cur_year: 2080, yy: 40, guess: 2040
The key is the (numeric) difference between the yy's of the two dates (today's date and your input date). And you need to adjust from today's YY (by +1 or -1) whenever the magnitude of the difference is 50 or greater:
$todays_yy = substr($date_today,2,2);
$inputs_yy = substr($date,2,2);
$correct_YY = substr($date_today,0,2) + int(($todays_yy-$inputs_yy)/50);
print $correct_YY . substr($date,-6);

Google sheet date of last revision in a row

Help!
In Google sheets, i just want one column to input the last date and time that any cell in a row is updated or revised.
For example:
a1 - should get the last revision date,
b1-z1 (any number of cells after a1) - everytime any cell in that row is updated or revised, a1 date is updated.
I want to apply the same script to more than one sheet.
I've found this script, which seemed to work fine, initially:
function onEdit(event){
var ss = SpreadsheetApp.getActiveSpreadsheet();
//Script Last Update Timing
var actSht = event.source.getActiveSheet();
var actRng = event.source.getActiveRange();
var activeCell = actSht.getActiveCell();
var row = activeCell.getRow();
var column = activeCell.getColumn();
if(row < 2) return; //If header row then return
var colNums = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]; //Coulmns, whose edit is considered
if(colNums.indexOf(column) == -1) return; //If column other than considered then return
var index = actRng.getRowIndex();
var dateCol = actSht.getLastColumn();
var lastCell = actSht.getRange(index,dateCol);
var date = Utilities.formatDate(new Date(), "GMT+5:30", "dd/MM/yyyy HH:mm:ss");
// Note: Insert the Date when someone update the row in the last coulmn
lastCell.setValue(date);
}
When I was testing it, it worked fine, but after that day it wasn't working or sometimes it works, or works when I do revisions myself but it doesn't work with the person/s I am sharing the file with.
I don't know anything about scripting but after a week of searching, I have opted to post, hoping someone can lead me to the right direction.
Any help would be greatly appreciated! Thank you in advance!
See if this helps:
function onEdit(e) {
if (e.range.columnStart < 5 || e.range.rowStart < 21) return;
e.source.getActiveSheet().getRange(e.range.rowStart, 1) //first col
.setValue(Utilities.formatDate(new Date(), "GMT+5:30", "dd/MM/yyyy HH:mm:ss"));
}