sqlite rounding 'error' - android

I'm using SQLite on and Android device.
I am attempting to convert a timestamp to a julian day, and round down the julian day by casting the result to an integer. For some reason, 2456902.0 is being rounded to 2456901. (I get the same result with the 'round' function as well)
I do need a workaround, but I would also like an explanation as to why this is happening if anyone has one.
My code and results are listed below:
cast(julianday((c.ts/1000), 'unixepoch') as int) as day,
julianday((c.ts/1000), 'unixepoch') as jd
When ts = 1409564846705, jd = 2456902.0, day = 2456901 (datetime is Mon Sep 01 04:47:26 CDT 2014)
When ts = 1409631153881, jd = 2456902.8, day = 2456902 (datetime is Mon Sep 01 23:12:33 CDT 2014)
I am trying to convert the timestamp to julian days to group records by day, but some data is falling into the wrong day (as you can see above, two records will be produced if I group by day, but the dates are part of the same day). I've resorted to: strftime('%d', datetime((c.ts/1000), 'unixepoch', 'localtime')) as day. The problem with this is that if I query for more than a month, there will be duplicate 'day of month's. Is there a better way to do this?

Julian day numbers have integer values at noon, so the start of a day is halfway between integers:
> SELECT julianday(1409631153881/1000, 'unixepoch', 'start of day');
2456902.5
It does not make sense to round Julian day numbers to integers unless you define precisely whether you want the previous or the next noon.
If you want just to group by the day, convert the value into a date string:
date(c.ts / 1000, 'unixepoch', 'localtime')
If you want a value that can be converted into a number, combine the year and the day of the year:
cast(strftime('%Y%j', c.ts / 1000, 'unixepoch', 'localtime') as int)
Alternatively, just divide the timestamp by the number of milliseconds in a day, but then you need to substract the proper offset of the timezone.

Related

How to parse 13-digit sqlite timestamp

The sqlite timestamp here is 13 digits, but how can one know its specific date. 1667458854391 should correspond to November 2022, but this year cannot be obtained regardless of interpretation or other conversions. I want to get time like 2022-11-03 15:00:54.
This method only works for ten digits
datetime('now','unixepoch', 'localtime')
This is sqllite timestamp, but product specific model does not know,only know that this timestamp is 13-digit just like these: 1667458854391 1667458752768
I tried to do this but it didn't feel compliant
datetime(substr(warehouse_inout_log.createTime,1,10),'unixepoch', 'localtime'),
The sqlite timestamp here is 13 digits, but how can one know its specific date.
You simply drop the 3 digits (the milliseconds) you do do this by dividing by 1000 or by using substring(createTime,1,10)
but this year cannot be obtained
If you want the year then you can use the strftime function with the %Y format String. e.g.
strftime('%Y',createTime/1000,'unixepoch','localtime')
I want to get time like 2022-11-03 15:00:54
What you have works. However it is simpler to use
datetime(createTime/1000,'unixepoch','localtime')
The following demonstrates the above (and also includes part of the official documentation regarding the formatting arguments):-
DROP TABLE IF EXISTS warehouse_inout_log;
CREATE TABLE IF NOT EXISTS warehouse_inout_log (createTime INTEGER);
INSERT INTO warehouse_inout_log VALUES
(1667458854391),(1667458752768),('1667458752768')
;
/*
The strftime() routine returns the date formatted according to the format string specified as the first argument. The format string supports the most common substitutions found in the strftime() function from the standard C library plus two new substitutions, %f and %J. The following is a complete list of valid strftime() substitutions:
%d day of month: 00
%f fractional seconds: SS.SSS
%H hour: 00-24
%j day of year: 001-366
%J Julian day number (fractional)
%m month: 01-12
%M minute: 00-59
%s seconds since 1970-01-01
%S seconds: 00-59
%w day of week 0-6 with Sunday==0
%W week of year: 00-53
%Y year: 0000-9999
%% %
*/
SELECT
strftime('%Y',createTime/1000,'unixepoch','localtime') AS createYear,
datetime(createTime/1000,'unixepoch','localtime') AS createDateTime,
strftime('%Y',substr(createTime,1,10),'unixepoch','localtime') AS createYearV2,
datetime(substr(createTime,1,10),'unixepoch','localtime') AS createDateTimeV2
FROM warehouse_inout_log
;
DROP TABLE IF EXISTS warehouse_inout_log;
Resulting in:-

How to format Ints from datePicker to date-string

I am able to get the date values from date picker:
override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {
Log.i("onDateSet", year.toString())
Log.i("onDateSet", month.toString())
Log.i("onDateSet", dayOfMonth.toString())
}
How can I format this ints into date-string, something like this for example: 2020-05-05
And I saw that the month always returning one month ago, if today is 5th month, it's returning 4th month.
Is it a bug or I just how it works and I need to add 1 to every month I'm getting from date picker?
The doc says that month int: the selected month (0-11 for compatibility with Calendar#MONTH), so yeah, this is the desired behavior and to format it to human readable you have to add 1 I suppose.
And for formatting a string you should probably manually concat the data you have
val date = "$year-${month+1}-$day"
(the quickest way to me, but you may choose some prettier one)
Alternatively you could do:
val date = LocalDate(year, monthOfYear + 1, dayOfMonth).toString("yyyy-MM-dd")
As mentioned in the AndroidSDK's Date class,
A month is represented by an integer from 0 to 11; 0 is January, 1 is February, and so forth; thus 11 is December.
An hour is represented by an integer from 0 to 23. Thus, the hour from midnight to 1 a.m. is hour 0, and the hour from noon to 1 p.m. is hour 12.
A minute is represented by an integer from 0 to 59 in the usual manner.
A second is represented by an integer from 0 to 61; the values 60 and 61 occur only for leap seconds.
Date and Year are represented in the usual manner, while the things mentioned above are represented with their respective rule.
Hence if its May, it will return 4, if its June it will return 5, and so on.
NOTE: Although this behavior may seem strange, it is consistent with the java.util.Calendar class (although it is not consistent with joda.time.DateTime).

Difference between 2 dates in days and in double

I am working on an app and i need to get the difference between the actual date and a date inserted by the user, in days and in double.
Any idea on how to make this? I've tried some things but without success.
First you must decide if you want to consider the time of the day and the timezone to calculate the difference, because this can lead to different results.
Example: current date (AKA "today") is April 17th or 18th, depending on where in the world you are. Actually, depending on the time of the day, there might be 3 different "todays" in the world, at the same time. What timezone are you using to calculate the difference?
the user will enter a date: only day, month and year? Will it enter the hours? Are you using the user's device's timezone or some specific zone?
the same questions apply to the current date
Depending on the choices you make, you might get a different result.
Anyway, I'd use this lib: http://www.threeten.org/threetenbp/
or java.time classes, if available in your API level. In both API's you can use the following.
To use a date (day-month-year only) and the device's default timezone, I'd choose the LocalDate class:
// current date in device's default timezone
LocalDate now = LocalDate.now();
// some date from input values (May 10th 2018)
LocalDate dt = LocalDate.of(2018, 5, 10);
// difference in days
long diff = ChronoUnit.DAYS.between(now, dt); // 23
If you want to consider the time of the day (hours, minutes, etc), use a LocalDateTime. But in this case, ChronoUnit.DAYS considers a day has passed when the time is >= the other (ex: the difference between April 17th at 10 AM and April 18th 9:59 AM is zero days, because the time of the day didn't reach 10 AM, so it didn't complete 1 day - with LocalDate this doesn't happen because this class doesn't have time-of-the-day fields and considers only the day, month and year).
If you want to consider everything (date, time, and timezone), including Daylight Saving Time transitions, use a ZonedDateTime instead (the code is very similar, the only difference is that you can choose a timezone to work with):
// current date/time in device's default timezone
ZonedDateTime now = ZonedDateTime.now(ZoneId.systemDefault());
// some date from input values (May 10th 2018, 10 AM in New York timezone)
ZonedDateTime dt = ZonedDateTime.of(2018, 5, 10, 10, 0, 0, 0, ZoneId.of("America/New_York"));
// difference in days
long diff = ChronoUnit.DAYS.between(now, dt); // 23
You can choose between the device's default timezone (ZoneId.systemDefault()) or a specific one (ZoneId.of("America/New_York")). You can check all the available timezones with ZoneId.getAvailableZoneIds().
Maybe it doesn't make sense to use current date in one timezone and user's date in another (I'd use the same for both), but that's up to you to decide.
Calendar c = Calendar.getInstance();
Calendar c2 // = what you will get from the user
long diff = c.getTimeInMillis()-c2.
double days = (double) diff/(1000*60*60*24);
that is what i have in mind.
I hope this helps
use this way
public static double getTimeDiffBetweenDate(Date startDateTime, Date finishDateTime) {
long diffInMilliseconds = finishDateTime.getTime() - startDateTime.getTime();
return TimeUnit.MILLISECONDS.toMinutes(diffInMilliseconds) / 60.0;
}

Convert jodatime period to days

Actually I'm trying to use the joda time library to manipulate dates. It seems preety good, but I've found a non-plus-ultra wall.
I have a jodatime period that I want to converto to days.
So, if my period has 1 year, 1 month, 1 week and 1 day, total should be:
365 + 30 (or 30 or 28 or 29) + 7 + 1 = 403 days aprox.
But, If I try
int total= myPeriod.edadHombre.toStandardDays().getDays();
...it throws an exception. What I'm doing wrong? Is "toStandardDays" the right way to obtain the total amount of days in a jodatime period?
While I try to understand why doesn't work, I've found another way to do it:
//I take a date (myDate) to create a start point and an end date:
DateTime startDate =new DateTime(myDate);
DateTime endDate = new DateTime(); //now()
Days someDays= Days.daysBetween(startDate, endDate);
int result=someDays.getDays();
That's all. Anyway, I hope that somebody give me an answer about toStandardDays...

Custom the display value of SimpleDateFormat in android

I currently work on a double value that represent the total consumed time
for example, I have a 260 that means 260 second is consumed
To display to user, I would like to format it
for example , it should be something like 0year,0month,0day,1hr,2min,30sec
But I found the SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); is not quite suit my case (seems the "h" in "hr" is conflicted with the hour symbol?)
So , how to change the HH:mm:ss to the case mentioned above?
Thanks for helping
DateFormat is useful to format dates, not an absolute value of time.
To achieve your goal, you can take a look to Formatter
Hope this sample helps you:
String total_consumed_time = String.format("%01d year, %01d month, %01d day, %01d hr, %01d min, %01d sec", time_year, time_month, time_day, time_hour, time_min, time_seg);
I didn't try that code, but I use similar workaround with an absolute time in milliseconds:
long time = 260000; // time in mseg
long time_hour = TimeUnit.MILLISECONDS.toHours(time);
time -= TimeUnit.HOURS.toMillis(time_hour);
long time_min = TimeUnit.MILLISECONDS.toMinutes(time);
time -= TimeUnit.MINUTES.toMillis(time_min);
long time_seg = TimeUnit.MILLISECONDS.toSeconds(time);
String total_time = String.format("%02d:%02d:%02d", time_hour, time_min, time_seg);
With a result of "00:04:20" (4 minutes and 20 seconds).
Accepted answer is in most cases okay for solving your problem, but gives wrong reason why not to use the class SimpleDateFormat. This format class is well suited for objects of type java.util.Date (which are kind of unix timestamps in milliseconds hence absolute value of time, NOT dates). In order to treat letters like "hr" as literals you need to escape them. Example code:
// create timestamp
java.util.Date jud = new java.util.Date(260 * 1000); // milliseconds
// create format for timestamp
SimpleDateFormat sdf =
new SimpleDateFormat("yyyy'year',M'month',d'day',H'hr',m'min',s'sec'");
// otherwise you will get extra offset time (example: in England +1 hour DST)
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
// output: 1970year,1month,1day,0hr,4min,20sec
String formatted = sdf.format(jud);
System.out.println(formatted);
Even with the applied and tricky time zone correction in code you face the problem that you have an output for the year 1970, a point in time. Hereby you can see that SimpleDateFormat does format timestamps well (absolute values in time) but NOT durations (amount resp. length of time). This semantic problem can also not be solved by the approach to use java.util.Formatter as soon as the input increases the day limit of 86400 seconds.
Old JDK and Android don't offer a built-in solution for evaluating time differences expressed in years, months and days. Java 8 does offer (limited) support with new API (class 'Period' only for date part, not time part). External libraries like JodaTime or my own one (actually only as alpha-version) give more support. JodaTime even offers a special PeriodFormatter which is ideal for solving your problem.

Categories

Resources