Related
First time post - I'm newer to java/JavaFx
I'm trying to get my code to save in 15 min incrementalist. The project has an Observable List that houses selectable appointment times.
ApptAddController.java
private final ObservableList<String> times = FXCollections.observableArrayList("8:00 AM", "9:00 AM", "10:00 AM", "11:00 AM", "12:00 PM", "1:00 PM", "2:00 PM", "3:00 PM", "4:00 PM");
ApptDB.Java
The "times" selected goes to the "saveAppt" method
public static boolean saveAppt(int id, String type, String contact, String location, String date, String time) {
//Time stamp for booking times
String tsStart = createTimeStamp(date, time, location, true);
String tsEnd = createTimeStamp(date, time, location, false);
try {
//get date for Appointment createDate
DateTimeFormatter dt = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
String nowString = LocalDateTime.now(Clock.systemUTC()).format(dt);
Statement statement = DBConnection.getConnection().createStatement();
//Query
String queryInsertOne = "INSERT INTO appointment(customerId, type, contact, location, start, end, createDate, lastUpdateBy, createdBy) values ('" + id + "', '" + type + "', '" + contact + "', '" + location + "','" + tsStart + "','" + tsEnd + "','" + nowString + "','" + UserDB.getCurrentUser() + "','" + UserDB.getCurrentUser() + "')";
int updateOne = statement.executeUpdate(queryInsertOne);
return true;
} catch (SQLException e) {
System.out.println("SQLException: " + e.getMessage());
}
return false;
}
The createTimeStamp method is hard coded in the following method with the "00":
public static String createTimeStamp(String date, String time, String location, boolean startMode) {
String t = time.split(":")[0];
int baseH = Integer.parseInt(t);
if(baseH < 8) {
baseH += 12;
}
if(!startMode) {
baseH += 1;
}
String baseD = String.format("%s %02d:%s", date, baseH, "00");
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd kk:mm");
LocalDateTime ldt = LocalDateTime.parse(baseD, dtf);
ZoneId zid;
zid = TimeZone.getDefault().toZoneId();
ZonedDateTime zdt = ldt.atZone(zid);
ZonedDateTime utcDate = zdt.withZoneSameInstant(ZoneId.of("UTC"));
ldt = utcDate.toLocalDateTime();
Timestamp ts = Timestamp.valueOf(ldt);
return ts.toString();
}
Id like to have the appointments be 15 min incrementals. The user will select times at random (8:00, 8:15, 8:30, 8:45). How do I get this code to detect what the user selects and puts int in the database accordingly. If I change "00" to "15" it will hard code every appt for 15 after.
Thanks for your time.
I am not able to follow your code well. So here's some general advice. I should say up front, managing appointments and schedules is a surprisingly complicated problem domain.
You seem to be focused on strings rather than appropriate data types, a common issue with new programmers. Learn to use smart objects, not dumb strings. Notice that none of the code shown below involves strings, except for presentation to users. Values are exchanged with the database as objects, without the use of strings.
Java offers an industry-leading assortment of date-time classes, in the java.time packages. So use them. LocalTime represents a time-of-day. LocalDate represents a date-only, without time-of-day, and without time zone.
For data-entry on the time of appointment, you should be collecting an hour and a minute. Work internally with 24-hour clock LocalTime objects.
List< LocalTime > hourTimes =
List.of(
LocalTime.of( 8 , 0 ) ,
LocalTime.of( 9 , 0 ) ,
LocalTime.of( 10 , 0 ) ,
LocalTime.of( 11 , 0 ) ,
LocalTime.of( 12 , 0 ) ,
LocalTime.of( 13 , 0 ) ,
LocalTime.of( 14 , 0 ) ,
LocalTime.of( 15 , 0 ) ,
LocalTime.of( 16 , 0 )
)
;
If your audience expects a 12-hour clock, present their display with a custom formatter. If your audience expects a 12-hour clock, present their display with a custom formatter.
Locale locale = Locale.US ;
DateTimeFormatter formatterHourOfDay = DateTimeFormatter.ofPattern ( "h a" ).withLocale ( locale ) ;
String output = hourTimes.get( 7 ).format( formatterHourOfDay ) ;
See similar code run live at IdeOne.com.
3 PM
Note that java.time uses immutable objects. So you can freely use the LocalTime object directly from the master list with no need to copy, no need to worry about its values being changed out from under your feet. This also means you can use java.time objects across threads, as they are designed to be thread-safe.
Keep a list of the possible minutes.
List< Integer > minutes = List.of( 0 , 15 , 30 , 45 ) ;
In you user-interface, let the use pick one of those four values, to be mated with their choice from hourTimes above.
Put these values together for your time-of-day to make a new LocalTime.
LocalTime localTime = hourTimes.get( 7 ).plusMinutes( minutes.get( 2 ) ) ; // Adding 0, 15, 30, or 45 minutes to the on-the-hour `LocalTime` object, resulting in another `LocalTime` object.
Combine the time-of-day with your intended date to get a LocalDateTime object.
LocalDate localDate = LocalDate.of( 2020 , Month.JANUARY , 23 ) ;
LocalDateTime localDateTime = LocalDateTime.of( localDate , localTime ) ;
Store that in a database column of SQL-standard type TIMESTAMP WITHOUT TIME ZONE. (that was "WITHOUT", not "WITH")
Generally best to use prepared statements in SQL rather than string-combining.
myPreparedStatement.setObject( … , localDateTime ) ;
In addition, record the intended time zone for that appointment. There is a data type in Java for this, ZoneId. But not in SQL. So record the zone name as text in your database.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
…
myPreparedStatement.setObject( … , z.toString() ) ; // Record name of zone as text.
By the way, no need to pass when the record was created or last updated. You should be configuring your database to set those value automatically on the server-side.
Separate your business logic from your user-interface. Notice that none of my code above relates to JavaFX.
Define a class just for the appointment. This class should know only the needs of an appointment, the business rules for what defines a valid appointment. This class should know nothing about the database, nor the user-interface.
I do not understand what you are trying to do with time zones in your use of ZonedDateTime. It seems you are trying to form a java.sql.Timestamp object. That is the wrong way to go for two reasons. First, that class is one of the terrible legacy date-time classes supplanted by java.time; never use it. Second, that is the wrong way to book appointments. Future appointments should be recorded as two separate parts, (a) date-with-time-of-day and (b) time zone.
Politicians around the world have shown a penchant for frequently changing the offset of the time zones under their jurisdiction. They do so with little, or even no, forewarning. So if you booked 3:45 PM for next January as a moment, as a specific point on the timeline, the time-of-day for that zone's wall-clock time might be changed by then, with 3:45 PM becoming 3:15 PM or 4:45 PM. Imagine if your software booked an appointment for the specific moment that was 3:45 PM before the zone changed its offset-from-UTC. The customers keeping their appointments will be appearing at 3 PM on the current wall-clock time while your appointment book software will show them as early (or late). To avoid this problem, do not schedule appointments as a moment, keep the date-with-time-of-day (LocalDateTime) separated from the time zone (ZoneId).
Combine the two (date-with-time-of-day & time zone) only when building out a schedule where you need specific moments.
ZoneId z = ZoneId.of( zoneNameFromDatabase ) ;
ZonedDateTime zdt = localDateTimeFromDatabase.atZone( z ) ;
If you need to see that moment in UTC, adjust by extracting a Instant object.
Instant instant = zdt.toInstant() ;
But do not store either the ZonedDateTime or Instant for the future. Store them only after the fact, when recording history. And even then, you record OffsetDateTime, as oddly the JDBC spec does not require support for ZonedDateTime or Instant. You would store that OffsetDateTime object in a column of SQL-standard type TIMESTAMP WITH TIME ZONE ("WITH", not "WITHOUT" as seen above).
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject( … , odt ) ; // Record history as a moment, a specific point on the timeline.
If I understand correctly, you can and should put LocalTime objects in your ObservableList. Rather than String objects. If so, do that.
Also use SQL datatype time for the times in your database (they may already be, I didn't notice this information in your question). Pass the LocalTime object to your database using a PrepatedStatement. For example:
yourPreparedStatement.setObject(5, startLocalTime);
yourPreparedStatement.setObject(6, endLocalTime);
Do similarly for date, etc., only using the appropriate types both on the Java and the SQL side.
To calculate end time as 15 minutes after start time:
LocalTime endLocalTime = startLocalTime.plusMinutes(15);
I know I am not giving you complete code, but I hope it will get you a step or two further.
I am working on a script where I need to keep checking for individual dates for a month. So far, I can directly check for a month, but I need it for a day, as it returns multiple values for a day.
The code is as follows:
SELECT * FROM table
WHERE end_datetime BETWEEN '2015-03-01 00:00:00' and '2015-04-01 00:00:00'
I need a code in java, where I can check for individual dates (example - between '2015-03-01 00:00:00' and '2015-03-02 00:00:00'; between '2015-03-02 00:00:00' and '2015-03-03 00:00:00' and so on, till the last date is reached, which is '2015-04-01 00:00:00'.
Half-Open
A common approach in date-time work is "Half-Open" (or Half-Closed). The idea is to making the beginning moment inclusive while the ending is exclusive. So a week runs from a Monday to a Monday, an hour runs from 02:00 to 03:00, and a day runs from 2015-03-01 00:00:00 to 2015-03-02 00:00:00. In other words, a day runs from the first moment of a day and goes up to, but does not include, the first moment of the next day.
This approach avoids various problem. The main problem is trying to determine the last moment of the day with infinite fractional second resolved to whole seconds or milliseconds or microseconds or nanoseconds. Better to say "The First of March is any date-time value >= 2015-03-01 00:00:00 AND < 2015-03-02 00:00:00" with an = in the first criterion but not in the second.
This means not using BETWEEN in SQL. Use a pair of comparisons >= and <.
Example SQL for obtaining events happening on first of March this year.
SELECT *
FROM event_
WHERE ( when_ >= '2015-03-01 00:00:00' )
AND ( when_ < '2015-03-02 00:00:00' )
;
Time Zone
The example above has a serious problem. It assumes we mean "today" in UTC time zone. Or perhaps the SQL session’s current default time zone is applied and adjusts the values. Either way it is messy.
Better to specify your desired/expected time zone rather than implicitly rely on some default.
If those date-time values were meant to be midnights in Montréal Québec, then we should say so. The word "midnight" seems to create confusion in this context of computer programming. I prefer the phrase "first moment of the day".
SELECT *
FROM event_
WHERE ( when_ >= '2015-03-01 00:00:00' AT TIME ZONE 'America/Montreal' )
AND ( when_ < '2015-03-02 00:00:00' AT TIME ZONE 'America/Montreal' )
;
Month
This same logic applies to doing a month. Go from first moment of March to first moment of April.
SELECT *
FROM event_
WHERE ( when_ >= '2015-03-01 00:00:00' AT TIME ZONE 'America/Montreal' )
AND ( when_ < '2015-04-01 00:00:00' AT TIME ZONE 'America/Montreal' )
;
Java
When working in Java, we can use the new java.time package built into Java 8 and later.
ISO 8601
First, for convenience, we convert your input strings to comply with standard formats defined by ISO 8601. The java.time framework uses ISO 8601 by default when parsing and generating string representations of date-time values. So no need for us to define explicit formatters.
String inputStart = "2015-03-01 00:00:00"; // Month of March.
String inputStop = "2015-04-01 00:00:00";
String inputStartStandard = inputStart.replace( " " , "T" );
String inputStopStandard = inputStop.replace( " " , "T" );
LocalDateTime
I assume your input strings represent the first moment of days in a certain time zone. I'll arbitrarily go with Québec as an example. The actual input strings lack any such information, so first we parse them as "homeless" LocalDateTime values without any time zone.
java.time.LocalDateTime localStart = LocalDateTime.parse( inputStartStandard );
java.time.LocalDateTime localStop = LocalDateTime.parse( inputStopStandard );
Next we adjust them to Québec time zone.
java.time.ZonedId zoneId = ZoneId.of( "America/Montreal" );
java.time.ZonedDateTime zdtStart = ZonedDateTime.of( localStart , zoneId );
java.time.ZonedDateTime zdtStop = ZonedDateTime.of( localStop , zoneId );
JDBC 4.2
Some day in the future we will be able to proceed to executing SQL at this point. But today most JDBC drivers have not yet been updated to JDBC 4.2, so they cannot directly handle the new java.time types.
Convert to old java.sql.Timestamp
While waiting for future JDBC drivers, we can use the new methods added to the old java.sql.Timestamp class to conveniently convert. The conversion requires an Instant object, which is a point on the timeline without time zone information (UTC basically). Our ZonedDateTime offer a toInstant method, just what we need.
java.sql.Timestamp tsStart = new java.sql.Timestamp( zdtStart.toInstant() );
java.sql.Timestamp tsStop = new java.sql.Timestamp( zdtStop.toInstant() );
No data loss
Note that all these mentioned classes, ( java.sql.Timestamp, java.time. ZonedDateTime, and java.time.Instant ), have nanosecond resolution of their fractional seconds. So no data loss involved going between them. Converting to the old java.util.Date/.Calendar or third-party Joda-Time library support only millisecond resolution, so may involve data loss.
Be aware of your database’s date-time resolution. Many databases such as Postgres use microsecond. Any value generated in java.time with nanoseconds will be truncated when saved to a database using microseconds. For example 2015-01-02 03:04:05.123456789 changes to 2015-01-02 03:04:05.123456, only six digits of fractional second.
PreparedStatement
Build the text for a SQL statement. While not required in this case, best to make a habit of using PreparedStatement to avoid SQL Injection security risk.
StringBuilder sql = new StringBuilder();
sql.append( "SELECT * " ).append( "\n" );
sql.append( "FROM event_ " ).append( "\n" );
sql.append( "WHERE ( when_ >= ? ) " ).append( "\n" );
sql.append( "AND ( when_rc_ < ? ) " ).append( "\n" );
sql.append( "ORDER BY when_ ASC " ).append( "\n" );
sql.append( ";" )append( "\n" );
Execute SQL
Lastly, execute the SQL. Pass the start and stop timestamp objects into the PreparedStatement.
try ( Connection conn = DatabaseHelper.instance().connectionInAutoCommitMode() ;
PreparedStatement pstmt = conn.prepareStatement( sql.toString() ); ) {
pstmt.setTimestamp( 1 , tsStart );
pstmt.setTimestamp( 2 , tsStop );
try ( ResultSet rs = pstmt.executeQuery(); ) {
while ( rs.next() ) {
// …
}
}
} catch ( SQLException ex ) {
logger.error( "SQLException during: " + message + "\n" + ex );
} catch ( Exception ex ) {
logger.error( "Exception during: " + message + "\n" + ex );
}
All this example code was hand-written without running, untested.
Day at a time
The Question is not clear. If you want a day at a time, loop by adding a day to the start.
ZonedDateTime zdtNextDay = zdtStart.plusDays( 1 );
You can also get the beginning of next month similarly, with call to plusMonths( 1 ).
ZonedDateTime zdtNextMonth = zdtStart.plusMonths( 1 );
You can test in your loop to see if the "next day" is still before the "next month" by calling isBefore.
if( zdtNextDay.isBefore( zdtNextMonth ) ) {
…
}
Complete month example
Here is a complete example of looping day-by-day of current month.
We must get the first moment of the day. To do that in java.time, we must start with a local date-only (LocalDate) where "local" means "any locality" without any specific time zone. Then we assign both a time zone and a time-of-day by calling atStartOfDay to produce a ZonedDateTime object. You might think the day starts at the time 00:00:00 but no, not always. Some time zones such as Palestine start Daylight Saving Time at midnight so the day starts at 01:00.
The old date-time classes before java.time, such as java.sql.Timestamp, implement toString methods that implicitly apply the JVM’s current default time zone. Though done with good intentions, this approach proved to be confusing. We see this in the code below. This code shows that when run in the United States west coast time zone with offset of -07:00, midnight in Québec with offset of -04:00 is three hours different. So midnight in Québec is reported as 9 PM (21:00) of the previous date out on the west coast.
java.time.ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtThisMonthStart = LocalDate.now( zoneId ).withDayOfMonth( 1 ).atStartOfDay( zoneId );
java.time.ZonedDateTime zdtNextMonthStart = zdtThisMonthStart.plusMonths( 1 );
java.time.ZonedDateTime zdtDayStart = zdtThisMonthStart; // Initialize variable to be modified in loop.
System.out.println( "JVM’s current default time zone applied implicitly by java.sql.Timestamp’s 'toString' method: " + java.util.TimeZone.getDefault( ) );
while ( zdtDayStart.isBefore( zdtNextMonthStart ) ) {
java.time.ZonedDateTime zdtNextDayStart = zdtDayStart.plusDays( 1 );
java.sql.Timestamp tsStart = java.sql.Timestamp.from( zdtDayStart.toInstant( ) );
java.sql.Timestamp tsStop = java.sql.Timestamp.from( zdtNextDayStart.toInstant( ) );
System.out.print( "In java.time, Day is: [" + zdtDayStart + "/" + zdtNextDayStart + "]. " );
System.out.println( "In java.sql.Timestamp, Day is: [" + tsStart + "/" + tsStop + "]" );
//
// … Do SQL work, such as the try-catch-catch seen above in this Answer.
//
// Prep for next loop. Increment to next day.
zdtDayStart = zdtDayStart.plusDays( 1 );
}
When run.
JVM’s current default time zone applied implicitly by java.sql.Timestamp’s 'toString' method: sun.util.calendar.ZoneInfo[id="US/Pacific",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=US/Pacific,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]
In java.time, Day is: [2015-08-01T00:00-04:00[America/Montreal]/2015-08-02T00:00-04:00[America/Montreal]]. In java.sql.Timestamp, Day is: [2015-07-31 21:00:00.0/2015-08-01 21:00:00.0]
…
In java.time, Day is: [2015-08-31T00:00-04:00[America/Montreal]/2015-09-01T00:00-04:00[America/Montreal]]. In java.sql.Timestamp, Day is: [2015-08-30 21:00:00.0/2015-08-31 21:00:00.0]
Option 1:
See if you need all data of dates then you first get all the records in single query order them by end_time. and then you can loop records.
Options 2:
You can also fetch records by date simply using '>' and '<' operator and you need to fire query in loop using prepared statement till last date is reached in loop. Keep increasing date using java Calendar in loop
how to add user timezone to utc
i am getting utc date like this
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-ddHH:mm:ss");
DateTime dateTime = formatter.withOffsetParsed().parseDateTime(getval[2]);
DateTime dateTimeUtc = dateTime.toDateTime(DateTimeZone.UTC);
Now i want to get user Timezone and add it to utc to convert that to localtime
UPDATE
i was able to get the user timezone but could add it to the utc
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-ddHH:mm:ss");
DateTime dateTime = formatter.withOffsetParsed().parseDateTime(getval[2]);
java.util.Calendar now = java.util.Calendar.getInstance();
java.util.TimeZone timeZone = now.getTimeZone();
DateTimeZone dtZone = DateTimeZone.forID(timeZone.getID());
DateTime dateTimeUtc = dateTime.toDateTime(DateTimeZone.UTC);
ofm.setDate(dateTimeUtc.toDateTime(dtZone).toDate());
This below code may help you to get the time zone of the user
//get Calendar instance
Calendar now = Calendar.getInstance();
//get current TimeZone using getTimeZone method of Calendar class
TimeZone timeZone = now.getTimeZone();
//display current TimeZone using getDisplayName() method of TimeZone class
System.out.println("Current TimeZone is : " + timeZone.getDisplayName());
also the below link helps you to convert user's timezone to UTC
link
java.time
The Joda-Time project was succeeded by the java.time framework defined in JSR 310. Here is the modern solution using those new classes found in Java 8 and later.
Your input format is nearly compliant with the ISO 8601 standard. The data is just missing the T between the date portion and the time-of-day portion, and is missing a Z on the end to indicate UTC. See if you can educate the publisher of your data about this important standard.
String input = "2019-01-23T01:23:45.123456789Z" ;
The java.time classes use the standard formats by default. So no need to specify a formatting pattern.
Instant instant = Instant.parse( input ) ;
instant.toString() = 2019-01-23T01:23:45.123456789Z
If you can get the input format changed, define a formatting pattern to match.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-ddHH:mm:ss" ) ;
Lacking any indicator of time zone or offset, we must parse as a LocalDateTime. Note that such an object does not represent a moment, is not a specific point on the timeline.
String input = "2019-01-2301:23:45" ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
ldt.toString() = 2019-01-23T01:23:45
You claim to be sure this date and time were intended to represent a moment in UTC. So we can apply an offset using the constant ZoneOffset.UTC to produce a OffsetDateTime.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;
odt.toString() = 2019-01-23T01:23:45Z
Then you said you want to adjust this into a specific time zone. Same moment, same point on the timeline, but different wall-clock time.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
zdt.toString() = 2019-01-23T02:23:45+01:00[Africa/Tunis]
As you can see, Tunisia on that date was running an hour ahead of UTC. So the time-of-day appears to be 2 AM rather than 1 AM.
Here's a small example that gets the difference from a list of time zones (in hours):
import java.util.Date;
import java.util.TimeZone;
public class StackOverflowTimeZone {
public static void main(String[] a) {
Date date = new Date();
for(int index = 0; index < TimeZone.getAvailableIDs().length; index++) {
System.out.println(TimeZone.getAvailableIDs()[index] + " offset from UTC: " + TimeZone.getTimeZone(TimeZone.getAvailableIDs()[index]).getOffset(date.getTime()) / (60 * 60 * 1000) + " hours.");
}
}
}
The abstract class TimeZone was designed to get the offset of a designated time zone from Coordinated Universal Time (UTC). There is a list of time zones that can be found by using the method TimeZone.getAvailableIDs(). After getting the offset, you will need to do a few small calculuations in order to find out whether the designated time zone is ahead or behind UTC. The sign (+/-) of your output should correlate to whether that designated time zone is ahead or behind UTC.
I want to query SQLite table and get records where the time field (which is a String representing long time in millis) is in the range of tomorrow from querying time.
I also have a field which holds the record date time like this:
dd/MM/yyyy, HH:mm:ss
How would you recommend implementing this?
As per your comment you are open to modify the schema for better performance. So it is better to save time as long (unix timestamp) in database and having an index on that. Once that is done you can simply get tomorrows date at 00:00 in local time zone and convert it to unix timestamp and query based on that. Here is how you can get tomorrows timestamp at 00:00,
public static long getTimeStampAt0000(long timestamp) {
Calendar givenDate = Calendar.getInstance();
givenDate.setTimeInMillis(timestamp);
givenDate.set(Calendar.HOUR_OF_DAY, 0);
givenDate.set(Calendar.MINUTE, 0);
givenDate.set(Calendar.SECOND, 0);
givenDate.set(Calendar.MILLISECOND, 0);
return givenDate.getTimeInMillis();
}
public static long getTimeStampAt0000ForTomorrow() {
long now = System.currentTimeMillis();
long nowAt0000 = getTimeStampAt0000(now);
if (now == nowAt0000) {
// if being queried at 00:00, we are assuming we want same or else we can just remove
// this condition
return nowAt0000;
} else {
return nowAt0000 + 86400000;
}
}
The SQLite doc says that it stores as:
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Are you certain you have milliseconds since epoch or seconds?
The bundled java.util.Date and Calendar classes are notoriously troublesome. Avoid them. Use either Joda-Time or the new java.time.* package in Java 8.
Note that both java.util.Date and Joda-Time DateTime use milliseconds since epoch, while the new java.time uses nanoseconds. Multiply by 1000L as needed.
When talking about "today" and "tomorrow" with a date-time, you must specify a time zone. The beginning and ending of a day depends on time zone.
// Simulate input.
long millis = DateTime.now().getMillis();
// Use a proper time zone name rather than 3-letter codes.
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" ); // Formerly known as Calcutta, India.
DateTime dateTime = new DateTime( millis, timeZone );
DateTime aDayLater = dateTime.plusDays( 1 );
// "Tomorrow" is a span of time.
DateTime startOfToday = new DateTime( timeZone ).withTimeAtStartOfDay();
// Interval comparison is done in "half-open" approach where beginning is inclusive and ending is exclusive.
Interval tomorrow = new Interval( startOfToday.plusDays( 1 ), startOfToday.plusDays( 2 ) );
boolean isDateTimeOccurringTomorrow = tomorrow.contains( dateTime );
boolean isADayLaterOccurringTomorrow = tomorrow.contains( aDayLater );
Dump to console…
System.out.println( "millis: " + millis );
System.out.println( "dateTime: " + dateTime );
System.out.println( "aDayLater: " + aDayLater );
System.out.println( "startOfToday: " + startOfToday );
System.out.println( "tomorrow: " + tomorrow );
System.out.println( "isDateTimeOccurringTomorrow: " + isDateTimeOccurringTomorrow );
System.out.println( "isADayLaterOccurringTomorrow: " + isADayLaterOccurringTomorrow );
When run…
millis: 1392883763016
dateTime: 2014-02-20T13:39:23.016+05:30
aDayLater: 2014-02-21T13:39:23.016+05:30
startOfToday: 2014-02-20T00:00:00.000+05:30
tomorrow: 2014-02-21T00:00:00.000+05:30/2014-02-22T00:00:00.000+05:30
isDateTimeOccurringTomorrow: false
isADayLaterOccurringTomorrow: true
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("PST"));
cal.setTime(new Date());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
Date resultdate = new Date(cal.getTimeInMillis());
sdf.setTimeZone(TimeZone.getTimeZone("PST"));
System.out.println("String date:"+sdf.format(resultdate));
System.out.println("Date:"+sdf.parse(sdf.format(resultdate)));
output:
String date:2011-12-29 09:01:58 PM
Date:Fri Dec 30 10:31:58 IST 2011
Problem:
sdf.format(resultdate) returning correct date and time to as per timezone. But,
sdf.parse(sdf.format(resultdate)) not returning correct date and time to as per timezone, how to fix this problem?
The Date class is merely a thin wrapper around the number of milli-seconds past the 'epoch' (January 1, 1970, 00:00:00 GMT). It doesn't store any timezone information. In your last call you are adding a date instance to a String which implicitly calls the toString() method. The toString() method will use the default timezone to create a String representing the instance (as it doesn't store any timezone info). Try modifying the last line to avoid using the toString() method.
System.out.println("Date:" + sdf.format(sdf.parse(sdf.format(resultdate))));
Try using joda-Time api for your convenience. Example is here
Unfortunatley Java date returns time in GMT only. When ever you want display in front end or some where, you need to use the formated String generated in your step1.
try the below code will, it will work.
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("PST"));
cal.setTime(new Date());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
Date resultdate = new Date(cal.getTimeInMillis());
sdf.setTimeZone(TimeZone.getTimeZone("PST"));
System.out.println("String date:"+sdf.format(resultdate));
System.out.println("Date:"+sdf2.parse(sdf.format(resultdate)));
Three-Letter Time Zone Codes
Avoid using the three-letter time zone codes. They are neither standardized nor unique. For example, IST means both India Standard Time and Irish Standard Time. Furthermore, the codes are meant to distinguish Daylight Saving Time (DST) but that only confuses matters.
Use proper descriptive time zone names to retrieve a time zone object that encompasses DST and other issues.
Joda-Time
The java.util.Date & Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use Joda-Time or the new java.time.* package bundled with Java 8.
In JodaTime, a DateTime object truly knows its own time zone (unlike java.util.Date). Usually we use the immutable classes in Joda-Time. So instead of changing the time zone in a DateTime object, we create a fresh new DateTime object based on the old but with a specified difference. A different time zone might be that difference.
Here is some example code.
DateTimeZone timeZone_India = DateTimeZone.forID( "Asia/Kolkata" );
DateTimeZone timeZone_Ireland = DateTimeZone.forID( "Europe/Dublin" );
DateTimeZone timeZone_US_West_Coast = DateTimeZone.forID( "America/Los_Angeles" );
DateTime now = new DateTime( timeZone_India );
System.out.println( "now in India: " + now );
System.out.println( "now in Ireland: " + now.withZone( timeZone_Ireland ) );
System.out.println( "now in US West Coast: " + now.withZone( timeZone_US_West_Coast ) );
System.out.println( "now in UTC/GMT: " + now.withZone( DateTimeZone.UTC ) );
When run…
now in India: 2014-02-10T13:52:27.875+05:30
now in Ireland: 2014-02-10T08:22:27.875Z
now in US West Coast: 2014-02-10T00:22:27.875-08:00
now in UTC/GMT: 2014-02-10T08:22:27.875Z
java.time
Same idea using the java.time classes which supplant Joda-Time.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = Instant.now();
Apply a time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
The instant and the zdt represent the same moment, the same point on the timeline. Each is seen through the lens of a different region’s wall-clock time.
Generate a String by either specifying a formatting pattern or by letting java.time automatically localize.
To localize, specify:
FormatStyle to determine how long or abbreviated should the string be.
Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, and such.
Example:
Locale l = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );