How to know if a Date object represents only Time in Java? - java

I'm trying to save data about date and time to List. Let's say, I have List<Date>. I have 2 types of formatting of strings: dd/mm/yy and hh:mm. Well, I'm able to easily format and create an instance of java.util.Date using SimpleDateFormat. However, when I try to print the object, the one that I saved time data into prints something like this:
Thu Jan 01 06:30:00 AZT 1970
How do I differentiate between these two and get the following output instead:
06:30
Note: Years may start earlier than 1970.
Thanks for the help and appreciate the effort.

How to know if a Date object represents only Time in Java?
There is no way to do this reliably. Every value of Date that you are using to represent a time also represents a valid date. And you can't distinguish the two cases ... except by using an unreliable heuristic.
The real problem is that you should not use Date to represent times.
A Date represents a single point in the time continuum.
A time is either a duration or multiple time points depending on how you use it. (It depends on your use-case.)
In fact, you probably not be using java.util.Date at all. Date is legacy Java class that has many API flaws. It was superseded in Java 8 by the classes and interfaces in the java.time package. These provide distinct classes for the various different concepts.
I recommend that you read the Date-Time trail in the Oracle Java Tutorial to get a basic understanding. This will help you decide the correct classes to choose for your use-case.
Time is complicated in the real world, and it is complicated in Java too.

Related

Best way to store time in java, in format of HH:MM

After doing my research I wasn't able to find a method or data type that should be used for variable in order to store time in format of HH:MM, I did find methods to get this from a string like "14:15:10", but I think this is not the best way, as I'll need to add or subtract from time. I tried doing this as a double, but ran into following issue, when you have a time like 05.45 stored and add 0.15 (or 15 minutes) to it, the result is 05.60 where as with HH:MM format you'd expect it to be 06.00.
I'm looked through java documentation and still am, but can't seem to find any way to achieve this, closest I got to is date format like dd/mm/yyyy hh:mm:ss
Use Joda Time. It provides much better operations to do date/time manipulation than standard java dates. If you want to use internal JDK classes, use java.util.Date.
Since Java 8, you can use the new API for dates and times, including Instant, ZonedDateTime and LocalDateTime. This removes the use for the third party library Joda time. It also makes calculations more easy and correct. The advice below is a bit dated but still has some good points.
—————
What you definitely should NOT do is store them in your own custom format. Store the Long value that represents the Unix Epoch.
A DateTime is nothing more than a number to a computer. This number represents the amount of seconds (or milliseconds) since 1970-01-01 00:00:00 UTC. It's beyond the scope of this answer to explain why this date was universally chosen but you can find this by searching for Unix Epoch or reading http://en.wikipedia.org/wiki/Unix_time.
This also means there is NO timezone information stored in a DateTime itself. It is important to keep this in mind when reasoning about dates and times. For things such as comparing DateTime objects, nothing concerning localization or timezones is done. Only when formatting time, which means as much as making it readable to humans, or for operations such as getting the beginning of the day, timezones come into play.
This is also why you shouldn't store the time like 20:11:15 in a string-like format because this information is meaningless without timezone information. I will give you 1 example here: Consider the moment when the clock is moved back 1 hour, such as when moving away from daylight savings time. It just happened in a lot of countries. What does your string 02:30 represent? The first or the second one?
Calculations such as subtraction are as easy as doing the same with numbers. For example: Date newDate = new Date(date1.getTime() - date2.getTime());. Or want to add an hour to a date? Date newDate = new Date(oldDate.getTime() + 1000 * 60 * 60);
If you need more complex stuff then using Joda time would be a good idea, as was already suggested. But it's perfectly possible to just do even that with the native libraries too.
If there's one resource that taught me a lot about date/time, it would be http://www.odi.ch/prog/design/datetime.php
Java has java.sql.Time format to work with time-of-day values. Just import it and create variables.
import java.sql.Time;
//now we can make time variables
Time myTime;
Just saw it on https://db.apache.org/derby/docs/10.4/ref/rrefsqlj21908.html
The answer that is right for your case depends on what you want to do.
Are you using a RDBMS as your persistence engine?
If so, are you already working with legacy data formats or are you building a database from the ground up?
Are you simply storing this data, or will you be doing extensive date arithmetic and/or precedence calculations?
Are you in one time zone or do you need to work with time instants across many time zones?
All of these things are important and factor into your decision of how to represent your times and dates.
If your needs require a lot of date arithmetic (eg. determining days between dates) or sorting based on timestamps, then consider using a floating point date format. The advantage of using a numeric format for timestamps is that doing date arithmetic and comparison/sorting operations becomes trivial; you merely do simple arithmetic. Another advantage is that floats and longs are primitive data types. They do not need to be serialized, they are already extremely lightweight, and everything you need to use them requires no external dependencies.
The main disadvantage to using numeric formats for timestamps is that they are not human friendly. You'll need to convert them to and from a String format to allow users to interact. Oftentimes, this is worth the effort. See: How do I use Julian Day Numbers with the Java Calendar API?
I recommend that you consider storing timestamps as Julian Day Numbers (JDNs) or Modified Julian Day Numbers (MJDs). Both will represent dates and times to millisecond precision using an 8 byte float. Algorithms for converting to and from display formats for both of these are highly standardized. They confer all the advantages of using numeric dates. Moreover, they are defined only for GMT/UTC which means that your timestamps are already universalizable across time zones right out of the box (as long as you localize properly).
If you dont want the full date object, your best bet is to store it in a string, but I personally would still recommend date as it also contains a lot of convenient methods that will come in handy. You can just get the time as a whole from a date object and ignore the rest.
In terms of "storing" a date, you should use a long. This is how the system sees it and how all calculations are performed. Yes, as some point out you will eventually need to create a String so a human can read it, but where people run into trouble is when they start thinking of a date in terms of format. Format is for readability, not for calculations. java.util.Date and java.util.Calendar are fraught with issues (Effective Java, Bloch, et. al. has plenty to say about it) but are still the norm if you need handy date operations.

Is there any way to convert date String of any format to millisecond in java?

Is there any function or library which gets a date in milliseconds, given a String?
This question shows how to convert a formatted String to a Date object, but is there any way to do this with an unformatted String?
Basically, the task is impossible. Here's an example:
01/04/2012
In the US, that means January 4th 2012. In Australia, that mean 1st April 2012.
Without knowing where you are and what date formats conventionally mean, it is impossible to accurately map an arbitrary date-like string to a date time value that matches what the user actually meant.
And even if you do know about the relevant local conventions, users have a remarkable propensity to be oblivious to ambiguity. Dealing with that may require deep domain knowledge (or mind reading skills!) to disambiguate the possible meanings.
When you think about it, this is why modern user interfaces typically use a date-picker widget of some kind when the user needs to enter a date / time
first convert the string to Date. From there you can get time in milis using Date.getTime() method

Why was Date.getTimezoneOffset deprecated?

The documentation for Date.getTimezoneOffset says:
Deprecated. As of JDK version 1.1, replaced by
-(Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000).
Why was it deprecated? Is there a shorter way (Apache Commons?) to get the offset from UTC in hours/minutes? I have a Date object ... should I convert it to JodaDate for this?
And before you ask why I want the UTC offset - it's just to log it, nothing more.
There are 2 questions here.
Why was Date.getTimezoneOffset deprecated?
I think it is because they actually deprecated nearly all methods of Date and moved their logic to calendar. We are expected to use generic set and get with the parameter that says which specific field we need. This approach has some advantages: less number of methods and the ability to run setters in a loop passing a different field each time. I personally used this technique a lot: it makes code shorter and easier to maintain.
Shortcut? But what's wrong with call
Calendar.get(Calendar.DST_OFFSET) comparing to
Calendar.getTimeZoneOffset()
As far as I can see the difference is 6 characters.
Joda is a very strong library and if you really have to write a lot of sophisticated date manipulation code switch to it. I personally use the standard java.util.Calendar and don't see any reason to use external libraries: good old calendar is good enough for me.
All of the date manipulation logic was moved out of Date once the Java implementers realized that it might need to be implemented differently for different types of calendars (hence the need to use a GregorianCalendar to retrieve this info now). A Date is now just a wrapper around a UTC time value.
Take care before you paste code from this page.
Perhaps just me but I believe that in order to get the tz offset in minutes you need to do
int tzOffsetMin = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET))/(1000*60);
rather than what the Javadoc says, which is:
int tzOffsetMin = -(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET))/(1000*60);
Calendar.ZONE_OFFSET gives you the standard offset (in msecs) from UTC. This doesn't change with DST. For example for US East Coast timezone this field will always be -6 hours regardless of DST.
Calendar.DST_OFFSET gives you the current DST offset (in msecs) - if any. For example during summer in a country that uses DST this field is likely to have the value +1 hour (1000*60*60 msecs).

How should date properties be defined in a java class?

I have a simple java object with several date properties and I always seem to change my mind on how to define them. Should the properties be defined as date objects or strings? The object is going to be used in struts 1.3 application with iBatis as the persistence layer and mysql as the database. The database columns are defined as datetime and they can possibly be null and I usually don’t care about the time portion.
public Date getForcastDate();
or
public String getForcastDate();
Most of the existing code base uses strings, but that just doesn’t seem quite right to me.
Keep your dates as Dates. That way you can change formatting depending on locales, check for invalid dates, sort by them etc.
By keeping them as strings you're potentially throwing away data (e.g. milliseconds if your formatter doesn't use them) and definitely behaviour.
Using strong-typing (e.g. keeping them as Dates) will aid in terms of development. Your method signatures become clearer, refactoring using IDE tooling becomes easier etc. Otherwise you end up with APIs that talk in nothing but strings, it's trivial to mix up parameters, and it becomes impossible to work out what's going on.
Tip: Check out Joda-Time as a better alternative to the standard java.util.Date.
I would use Date object because it cleaner to store a Date and convert it to a String when needed. Otherwise you have to hard code a formatted date into a String field.
I would never use Strings in this cas as what would today be 8/3/11 or 3/8/11 or 2011-03-08. This is really a specific case of trying to use the most restrictive type/class possible for a variable. This is so that you can understand its behaviour more fully, both by having a restricted or specialised set of methods and by helping documentation of other classes using it. Using a Date here would allow you to use a Calendar object to add days or months. Conversion to or from a string only needs to be done for input and output.
In practice if they were only dates I would crete my own Date class so could ignore times or use JodaTime which provides easier manipulation than the java Date
In my code I always use the most high level object. In this case I would suggest - Calendar. Here is separate discussion about Date and Calendar. I always think this way - converting Calendar/Date to String is simple - use SimpleDateFormatter. But very often you will need to do something with the date (add several days or hours, subtract a year, handle timezones etc) and then each time you would have to convert it from String to Calendar/Date.
Date if you had to, but java.util.Calendar would probably be more appropriate nowadays. With a String you'd have to worry about format like #jzd mentioned. With Calendar, you can easily switch between formats. Also Calendar lets you get at the date with Calendar.getTime()

How to parse four digit year only (with Joda Time)?

Is there a way to force Joda time to parse dates only when they contain four digit years? For example:
2009-11-11 - should parse
09-11-11 - should not parse
Tried the following code:
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
DateTimeFormatter formatter = builder.appendYear(4, 4).appendLiteral('-').appendMonthOfYear(1).appendLiteral('-').appendDayOfMonth(1).toFormatter();
formatter.parseDateTime("09-11-11");
Parses into 0009-11-11. Apparently minDigits in the method appendYear are only used for formatting when printing out the date.
The result is the same if I use appendYearOfEra(). If I use appendYearOfCentury(), it parses the year into 1909 instead.
We are implementing a general data parser, which will recognize various types of inputs. Also the example is a shortened form of the real deal (for simplicity). Real life scenarios parses dates which can have weekdays, months as words, time, zone and different characters separating month, day and year. Therefore, writing a RegEx or checking the content/length of the string can prove rather difficult.
Some real examples could look like this:
2009-11-11
Wednesday 2009-11-11T15:00:00
2009/11/11 15:00
and many more...
DateTimeFormatterBuilder#appendFixedDecimal() may well do what you need.
Alternatively, you could implement the DateTimeParser interface to create whatever parser you want and pass that into the DateTimeFormatterBuilder.
You can check the length of the date string.
You can build extremely specific parsers and formatters using DateTimeFormatterBuilder. There's generally no need to use this class directly, since most common formats are more easily available elsewhere in the API, but this is the builder class they all use under the covers.
What do you want to get from a user who enters '0001-01-01' as the date (that is, they entered 4 digits for the year, but the first three were zeroes)? What about '0999-12-31'? And '999-12-31'? And what about '10000-01-01' - the infamous Y10K1 problem?
If that is a legitimate value, then you are stuck with discovering the length of what the user typed as the year portion of the date (probably after any other parsing has been done), and making sure it is at least (or is it exactly?) four digits.
If that is not a legitimate value, then you are stuck with checking the year value after the date is parsed.
Or you can take the code and modify it so it includes your preferred definition of valid year.
1 I do not plan to start working on fixing the Y10K problem before 5000-01-02.

Categories

Resources