How to indicate some fields are not supported - java

Trying to move from Calendar to the new Java 8 time on Android. Is there a way to indicate that a time or date field is not supported? I can use the 'Truncate' method that will set all time fields of a shorter duration to zero, so a time stamp like 2020-09-30T10:37:15.345-04:00 can be truncated say at the minutes level. But that will leave 2020-09-30T10:00:00.00-04:00.
However, what I want to indicate is that the clock does not have minutes or less precision so that when one tries to read the minutes or seconds, there will be some indication that there are no such fields or that they are unknown. Zero is a valid value.
Right now in the Calendar case I have to add numerous methods to a class to indicate that. For example, I made a class called TimeStruct which wraps a Calendar. If I take a time stamp like 2020-10-01T04:55 it does not have minutes. So to keep that information I have a variable 'isSecondsSet' and set it to false. I create the Calendar from the elements I DO have. But as soon as I call something like Calendar.getTimeInMillis() the seconds and milliseconds fields get set to 0 and are indicated as set. So my additional variables let me know that there was no seconds field.
I was hoping that the new classes would no longer require me to keep my own indicators and I would also be able to parse something like 2020-10-01T04:55. I could not, but I could parse a full time stamp. So if I do that and truncate, can I indicate that the truncated fields are not supported? That way I wont use a value of 0 in the seconds.

Related

Text cannot be parsed to a Duration in java8

I am trying to parse a text to duration as follow:
final Duration duration = TimeUtil.parseDuration("1.0:00:00");
But I get the following error,
Text cannot be parsed to a Duration
so can anyone tells me where my problem is?
If you are using protocol buffers' TimeUtil you specify a duration with seconds separated from nanoseconds by a period. The value may be lead by a minus sign, if the duration is negative (so that adding the duration to a time would move into the past relative to the time). The string must end in "s".
You can see the pretty simple parse and toString of a protocol buffer's duration in the public git[hub] repo's TimeUtil.
Given the type of duration, I'm guessing they're used for calculations on date-times that are internally represented as signed 64 bit nano seconds since unix epoch.
In other words it looks like these are valid durations:
"1s" // one second forward
"1.0s" // one second forward
"1.01s" // one second, 10,000,000 nano seconds forward
"-1.01s" // one second, 10,000,000 nano seconds backward
"60s" // one minute forward
"-86400s" // yesterday (one day backward)
// [assuming no daylight saving changes or leap seconds happened]
The Protocol Buffers' TimeUtil.parseDuration would not give you the error message you say you got, and is not at all like Duration.parse, which is more clearly documented and might give that kind of error message.
If guessed API:
parseDuration(String duration) takes as parameters:
duration - "3h" or "2mn" or "7s" or null.
Taken from java.lang.Object ninja.utils.TimeUtil API. It returns the number of seconds.
Then "1.0:00:00" is obviously not to be parsed.

Time - Specify X seconds / minutes, and basic arithmetic

I am wondering how one would go about specifing a certain amount time, say X seconds. I'm writing the behaviour for a class that represents a Till (as in, a supermarket till), and whish to specify how long it takes to check out 1 item.
I'm doing this so once I receive the number of items a customer has, the time taken to serve the customer is simply:
ITEM_CHECKOUT_TIME * NumberOfItems;
ITEM_CHECKOUT_TIME would be a constant, and what I wish to specify. Some basic arithmetic would be done on this constant, like above.
Sure, I could use a double to represent the time, but I was wondering if it's actually possible with the Time classes, or anything else specifically for this task.
Thanks!
I would not use a double to represent time. I would probably represent it as a whole number of milliseconds (or nanoseconds). If you're looking for something fancier, you might want to look at the Duration class in the Joda-Time library:
http://joda-time.sourceforge.net/key_duration.html

Java equivalent of C's _timezone, _daylight and time()

With this C code:
int a = time(NULL);
_daylight = 0;
_timezone = 0;
int b = time(NULL);
assert(a != b);
"a" and "b" will have different values (and not just because they are called a few milliseconds apart). The difference will be whatever the offset of your PC's timezone is from UTC time. Also, changing the _daylight and _timezone values effect pretty much every other function I might use in my C app -- I assume because they all respect that value.
Is there anything like that in Java, or specifically for Java on Android OS? I tried TimeZone.setDefault(), but that didn't change the value that System.currentTimeMillis() returned, so I assume it isn't going to have a "global" effect like the C variables.
I understand that System.currentTimeMillis() is different than time(), in that it "always" returns the number of millis since now and epoch, and the time() function allows you to get "false" (fudged) values that are adjusted according to these global variables you can set.
Just trying to emulate a legacy C app on Android OS. It clears those _timezone and _daylight values which pretty much means it ignores any timezones. So if a user running the app on the west coast enters a time of 3pm, and then they change their timezone settings, or a user on the est coast views that item, it will still show as 3pm.
I know I can use the Calendar object and other methods to make sure I do the proper conversions, but I'd rather just have an easy "I don't care about timezones" settings like I did in the C app and then truely not have to worry about them.
Edit: I would still like to hear what other options I have, but for now I came up with this Java code that I'll do my best to always use for any code that needs to mimic the C app:
// IMPORTANT: Use this function everywhere a Calendar object is needed, instead of calling
// Calendar.getInstance() directly. This returns the correct kludged time that matches
// what our PC application uses (_daylight=0, _timezone=0, time(NULL) in C)
public static Calendar GetCalendarInstance()
{
// Get the current UTC time
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
// Offset it by the system time zone offset.
// This mimics what the C time(NULL) function does when you set _timezone=0 and _daylight=0
cal.add(Calendar.MILLISECOND, TimeZone.getDefault().getOffset(cal.getTimeInMillis()));
return(cal);
}
Also, I did already find one place in my Android app that I need the real, not adjusted, system time (when using AlarmManager to schedule a PendingIntent). So I guess "global" could be dangerous either way. I still think 95% of my code will be using the version that mimics the C app though, so if possible I'd like to default to that and then only have to do special handling for the other few places.

How can i separate instances of a class on behalf of their time of creation using java?

Suppose i have 100 instances of a class. I want to make arrays of those instances on behalf of their time of creation. For example there are 40 object which are created in september-2011 and 60 objects which are created in october-2011. Every instance has its time of creation which has type long. How can i tell my java program to make array of all instances which are created in september and another array which contains all instances which are created in october. I created time of creation using this line of code:
Date currentDate = new Date();
long timeOfCreation = currentDate.getTime();
Thanks in advance.
Well, you iterate over the instances, check their creation time and put them into the according list (I'd not use an array here, you could later convert the lists to arrays if you need to).
Basically, it's just a matter of getting the month from the date (you can create a Date object from the timestamp) which should be doable using Calendar (or yet better: use Joda Time).
If the intervals are non-standard (e.g. from 15th to 15th) you might need a start and end value to compare against.
Edit:
If you store those timestamps in your database, you could just create a query to get all the instances between start and end date of each interval (... WHERE timeOfCreation BETWEEN <start> and <end>, note that <start> and <end> are just placeholders for your parameters). Then call that query for every interval you are interested in, e.g. start = September 1st 00:00:00,000 and end = September 30th 23:59:59,999.

another strange behaviour with GregorianCalendar

Take a look at the piece of code bellow:
Calendar today1 = Calendar.getInstance();
today1.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
System.out.println(today1.getTime());
Calendar today2 = new GregorianCalendar(2010, Calendar.JULY, 14);
today2.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
System.out.println(today2.getTime());
I'm quite confused... Assuming I am running it today as July 14th, 2010, the output is:
Fri Jul 16 14:23:23 PDT 2010
Wed Jul 14 00:00:00 PDT 2010
The most annoying thing is that if I add today2.getTimeInMillis() (or any other get() method) it will produce consistent result. For the code bellow:
Calendar today2 = new GregorianCalendar(2010, Calendar.JULY, 14);
today2.getTimeInMillis();
today2.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
System.out.println(today2.getTime());
The result is:
Fri Jul 16 00:00:00 PDT 2010
The answer is actually documented in the JavaDoc for java.util.Calendar
Quoted here:
set(f, value) changes calendar field f to value. In addition, it sets an internal member variable to indicate that calendar field f has been changed. Although field f is changed
immediately, the calendar's
milliseconds is not recomputed until
the next call to get(), getTime(), or
getTimeInMillis() is made.
So that explains the behavior you are seeing, but I concur with another responder to your question that you should consider JodaTime if you're going to do a lot of Date coding.
You should in fact be using Calendar#getInstance() to get an instance and not new GregorianCalendar(). Replace that line by
Calendar today2 = Calendar.getInstance();
today2.set(2010, Calendar.JULY, 14);
and it will go well.
Sorry, no detailed explanation for the behaviour, expect that Calendar along with java.util.Date are one of the major epic failures in the current Java SE API. If you're doing intensive date/time operations, then I'd recommend to have a look at JodaTime. The upcoming new Java 7 will ship with an improved date/time API based on JodaTime (JSR-310).
(Sorry for the edit, I wanted this to be a little more readable, but couldn't get it right when I originally wrote the answer...now it's essay length, but there you go...)
Just to add to what's already been said, the issue arises from the returned Calendar instances being prepared differently. I personally feel like this is a design flaw, but there may be good reason for it.
When you call Calendar.getInstance(), it creates a new GregorianCalendar using the default constructor. This constructor calls setCurrentTimeMillis(time) with the current system time, and then calls the protected method complete().
However, when you create a new GregorianCalendar using the constructor that you did, complete() is never called; instead, among other things, only set(field, value) is called for the various bits of information that is provided. This is all well and good, but it has some confusing consequences.
When complete() is called in the first case, the member variables dustmachine alluded to are checked to determine what information should be recalculated. This results in a branch that forces calculation all of the fields (DAY, WEEK_OF_MONTH, etc.). Note that Calendar is indeed lazy; it just happens that using this method of instantiation forces an explicit recalculation (or in this case initial calculation) on the spot.
So, what impact does this have? Given that no upfront field computation was performed in the case of the second object creation, the two objects have vastly different states. The first has all of its field information populated, while the second only has the information which you provided. When you call the various get*() methods, it shouldn't matter, because any changes should provoke the lazy recalculation step when you retrieve the information. However, the order in which this recalculation occurs exposes the differences between the two varying initial states.
In your particular case, this is due to the following relevant code in computeTime(), which is necessarily invoked to compute the correct time when you request it with getTime():
boolean weekMonthSet = isSet[WEEK_OF_MONTH] || isSet[DAY_OF_WEEK_IN_MONTH];
...
boolean useDate = isSet[DATE];
if (useDate && (lastDateFieldSet == DAY_OF_WEEK
|| lastDateFieldSet == WEEK_OF_MONTH
|| lastDateFieldSet == DAY_OF_WEEK_IN_MONTH)) {
useDate = !(isSet[DAY_OF_WEEK] && weekMonthSet);
}
In the first case, all fields are set due to that initial calculation. This allows weekMonthSet to be true, which, along with the DAY_OF_WEEK that you provided in your call to set(field, value) being set, causes useDate to be false.
However, in the second case, as no fields have been calculated, the only fields set are the ones you provided in the constructor and in the subsequent set(field, value) call. Thus, useDate will remain true, because isSet[DATE] is true per your constructor, but weekMonthSet is false as the other fields in the object have not been computed anywhere, nor set by you.
When useDate is true, as implied, it uses your date information to generate the value for the time. When useDate is false, it's able to use your DAY_OF_WEEK information to compute the time you expect, resulting in the difference you see.
Finally, this raises the question of why calling getTimeInMillis() before calling getTime() will fix the unexpected behaviour. As it turns out, the fields will be recalculated as a result of your set(field, value) call in both objects. This just happens to occur after the time is calculated, for whatever (probably genuine) reason. Therefore, forcing the time to be calculated once on the second Calendar will essentially align the states of the two objects. After that, I believe the calls to get*() should all work consistently for both objects.
Ideally, the constructor you used in the second case should perform this initial calculation step in the name of consistency (although maybe for reasons of performance this wouldn't be preferred), but it doesn't, and this is what you get.
So, in short, as the others mentioned, JodaTime is your friend, and clearly these classes are less so. :)

Categories

Resources