001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.util.time; 018 019import java.text.ParseException; 020import java.text.SimpleDateFormat; 021import java.util.Calendar; 022import java.util.Date; 023import java.util.GregorianCalendar; 024import java.util.Locale; 025import java.util.TimeZone; 026 027/** 028 * An immutable <code>Time</code> class that represents a specific point in time. The underlying 029 * representation is a <code>long</code> value which holds a number of milliseconds since January 1, 030 * 1970, 0:00 GMT. To represent a duration of time, such as "6 seconds", use the 031 * <code>Duration</code> class. To represent a time period with a start and end time, use the 032 * <code>TimeFrame</code> class. To represent a time of day, use the <code>TimeOfDay</code> class. 033 * 034 * @author Jonathan Locke 035 * @since 1.2.6 036 * 037 * @deprecated Since Wicket 9 this class is obsolete and no more used. It will be removed in Wicket 10. Use {@link java.time.Instant} instead 038 */ 039@Deprecated 040public final class Time extends AbstractTime 041{ 042 private static final long serialVersionUID = 1L; 043 044 /** the beginning of UNIX time: January 1, 1970, 0:00 GMT. */ 045 public static final Time START_OF_UNIX_TIME = millis(0); 046 047 /** parser in 'yyyy.MM.dd' format. */ 048 private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd", 049 Locale.ENGLISH); 050 051 /** parser in 'yyyy.MM.dd-h.mma' format. */ 052 private static final SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy.MM.dd-h.mma", 053 Locale.ENGLISH); 054 055 /** required for rfc1123 date format */ 056 private static final String[] DAYS = 057 {"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 058 059 /** required for rfc1123 date format */ 060 private static final String[] MONTHS = 061 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"}; 062 063 /** time zone for greenwich mean time */ 064 public static final TimeZone GMT = TimeZone.getTimeZone("GMT"); 065 066 /** 067 * Retrieves a <code>Time</code> instance based on the current time. 068 * 069 * @return the current <code>Time</code> 070 */ 071 public static Time now() 072 { 073 return millis(System.currentTimeMillis()); 074 } 075 076 /** 077 * Retrieves a <code>Time</code> instance based on the given milliseconds. 078 * 079 * @param time 080 * the <code>Time</code> value in milliseconds since START_OF_UNIX_TIME 081 * @return a corresponding immutable <code>Time</code> object 082 */ 083 public static Time millis(final long time) 084 { 085 return new Time(time); 086 } 087 088 /** 089 * Retrieves a <code>Time</code> instance by parsing 'yyyy.MM.dd' format. 090 * 091 * @param calendar 092 * the <code>Calendar</code> to use when parsing date <code>String</code> 093 * @param string 094 * the <code>String</code> to parse 095 * @return the time 096 * @throws ParseException 097 */ 098 public static Time parseDate(final Calendar calendar, final String string) 099 throws ParseException 100 { 101 synchronized (dateFormat) 102 { 103 synchronized (calendar) 104 { 105 dateFormat.setCalendar(calendar); 106 107 return valueOf(dateFormat.parse(string)); 108 } 109 } 110 } 111 112 /** 113 * Retrieves a <code>Time</code> instance by parsing 'yyyy.MM.dd' format using a local time 114 * <code>Calendar</code>. 115 * 116 * @param string 117 * the <code>String</code> to parse 118 * @return the time 119 * @throws ParseException 120 */ 121 public static Time parseDate(final String string) throws ParseException 122 { 123 return parseDate(localtime, string); 124 } 125 126 /** 127 * Retrieves a <code>Time</code> instance by parsing 'yyyy.MM.dd-h.mma' format. 128 * 129 * @param calendar 130 * the <code>Calendar</code> to use when parsing the <code>String</code> 131 * @param string 132 * the <code>String</code> to parse 133 * @return an immutable UNIX <code>Time</code> value 134 * @throws ParseException 135 */ 136 public static Time valueOf(final Calendar calendar, final String string) throws ParseException 137 { 138 synchronized (dateTimeFormat) 139 { 140 synchronized (calendar) 141 { 142 dateTimeFormat.setCalendar(calendar); 143 144 return valueOf(dateTimeFormat.parse(string)); 145 } 146 } 147 } 148 149 /** 150 * Retrieves a <code>Time</code> instance based on the given <code>Calendar</code> and 151 * {@link TimeOfDay} objects. 152 * 153 * @param calendar 154 * the <code>Calendar</code> to use 155 * @param timeOfDay 156 * the time of day 157 * @return a <code>Time</code> value for the time of day today 158 */ 159 public static Time valueOf(final Calendar calendar, final TimeOfDay timeOfDay) 160 { 161 synchronized (calendar) 162 { 163 // Set time to midnight today 164 calendar.setTimeInMillis(System.currentTimeMillis()); 165 calendar.set(Calendar.HOUR_OF_DAY, 0); // WICKET-2349 166 calendar.set(Calendar.MINUTE, 0); 167 calendar.set(Calendar.SECOND, 0); 168 calendar.set(Calendar.MILLISECOND, 0); // WICKET-1670 169 170 // Add time of day milliseconds to midnight 171 return millis(calendar.getTimeInMillis() + timeOfDay.getMilliseconds()); 172 } 173 } 174 175 /** 176 * Retrieves a <code>Time</code> instance based on the given <code>Date</code> object. 177 * 178 * @param date 179 * a <code>java.util.Date</code> object 180 * @return a corresponding immutable <code>Time</code> object 181 */ 182 public static Time valueOf(final Date date) 183 { 184 return new Time(date.getTime()); 185 } 186 187 /** 188 * Retrieves a <code>Time</code> instance by parsing 'yyyy.MM.dd-h.mma' format. 189 * 190 * @param string 191 * the <code>String</code> to parse 192 * @return the <code>Time</code> instance 193 * @throws ParseException 194 */ 195 public static Time valueOf(final String string) throws ParseException 196 { 197 return valueOf(localtime, string); 198 } 199 200 /** 201 * Retrieves a <code>Time</code> instance by parsing 'pattern' format. 202 * 203 * @param string 204 * input 205 * @param pattern 206 * the pattern to parse 207 * @return a <code>Time</code> instance that resulted from parsing the given <code>String</code> 208 * @throws ParseException 209 */ 210 public static Time valueOf(final String string, final String pattern) throws ParseException 211 { 212 final SimpleDateFormat dateTimeFormat = new SimpleDateFormat(pattern, Locale.ENGLISH); 213 dateTimeFormat.setCalendar(localtime); 214 return valueOf(dateTimeFormat.parse(string)); 215 } 216 217 /** 218 * Retrieves a <code>Time</code> instance based on the given {@link TimeOfDay} object. 219 * 220 * @param timeOfDay 221 * the time of day in local time 222 * @return a <code>Time</code> value for the time of day today 223 */ 224 public static Time valueOf(final TimeOfDay timeOfDay) 225 { 226 return valueOf(localtime, timeOfDay); 227 } 228 229 /** 230 * Private constructor forces use of static factory methods. 231 * 232 * @param time 233 * the <code>Time</code> value in milliseconds since START_OF_UNIX_TIME 234 */ 235 private Time(final long time) 236 { 237 super(time); 238 } 239 240 /** 241 * Adds the given <code>Duration</code> to this <code>Time</code> object, moving the time into 242 * the future. 243 * 244 * @param duration 245 * the <code>Duration</code> to add 246 * @return this <code>Time</code> + <code>Duration</code> 247 */ 248 public Time add(final Duration duration) 249 { 250 return millis(getMilliseconds() + duration.getMilliseconds()); 251 } 252 253 /** 254 * Calculates the amount of time that has elapsed since this <code>Time</code> value. 255 * 256 * @return the amount of time that has elapsed since this <code>Time</code> value 257 * @throws IllegalStateException 258 * thrown if this <code>Time</code> value is in the future 259 */ 260 public Duration elapsedSince() 261 { 262 final Time now = now(); 263 if (this.greaterThan(now)) 264 { 265 throw new IllegalStateException("This time is in the future"); 266 } 267 return now.subtract(this); 268 } 269 270 /** 271 * Retrieves the <code>Duration</code> from now to this <code>Time</code> value. If this 272 * <code>Time</code> value is in the past, then the <code>Duration</code> returned will be 273 * negative. Otherwise, it will be the number of milliseconds from now to this <code>Time</code> 274 * . 275 * 276 * @return the <code>Duration</code> from now to this <code>Time</code> value 277 */ 278 public Duration fromNow() 279 { 280 return subtract(now()); 281 } 282 283 /** 284 * Retrieves the value of a field from the given <code>Calendar</code>. 285 * 286 * @param calendar 287 * the <code>Calendar</code> to use 288 * @param field 289 * the <code>Calendar</code> field to get 290 * @return the field's value for this point in time on the given <code>Calendar</code> 291 */ 292 public int get(final Calendar calendar, final int field) 293 { 294 synchronized (calendar) 295 { 296 calendar.setTimeInMillis(getMilliseconds()); 297 298 return calendar.get(field); 299 } 300 } 301 302 /** 303 * Retrieves the value of a field. 304 * 305 * @param field 306 * the <code>Calendar</code> field to get 307 * @return the field's value (in local time) 308 */ 309 public int get(final int field) 310 { 311 return get(localtime, field); 312 } 313 314 /** 315 * Retrieves the day of month field of the current <code>Calendar</code>. 316 * 317 * @return the day of month field value 318 */ 319 public int getDayOfMonth() 320 { 321 return getDayOfMonth(localtime); 322 } 323 324 /** 325 * Retrieves the day of month field of the given <code>Calendar</code>. 326 * 327 * @param calendar 328 * the <code>Calendar</code> to get the field value from 329 * @return the day of month field value 330 */ 331 public int getDayOfMonth(final Calendar calendar) 332 { 333 return get(calendar, Calendar.DAY_OF_MONTH); 334 } 335 336 /** 337 * Retrieves the hour field of the current <code>Calendar</code>. 338 * 339 * @return the hour field value 340 */ 341 public int getHour() 342 { 343 return getHour(localtime); 344 } 345 346 /** 347 * Retrieves the hour field of the given <code>Calendar</code>. 348 * 349 * @param calendar 350 * the <code>Calendar</code> to get the field value from 351 * @return the hour field value 352 */ 353 public int getHour(final Calendar calendar) 354 { 355 return get(calendar, Calendar.HOUR_OF_DAY); 356 } 357 358 /** 359 * Retrieves the minute field of the current <code>Calendar</code>. 360 * 361 * @return the minute field value 362 */ 363 public int getMinute() 364 { 365 return getMinute(localtime); 366 } 367 368 /** 369 * Retrieves the minute field of the given <code>Calendar</code>. 370 * 371 * @param calendar 372 * the <code>Calendar</code> from which to get the field value 373 * @return the minute field value 374 */ 375 public int getMinute(final Calendar calendar) 376 { 377 return get(calendar, Calendar.MINUTE); 378 } 379 380 /** 381 * Retrieves the month field of the current <code>Calendar</code>. 382 * 383 * @return the month field value 384 */ 385 public int getMonth() 386 { 387 return getMonth(localtime); 388 } 389 390 /** 391 * Retrieves the month field of the given <code>Calendar</code>. 392 * 393 * @param calendar 394 * the <code>Calendar</code> from which to get the field value 395 * @return the month field value 396 */ 397 public int getMonth(final Calendar calendar) 398 { 399 return get(calendar, Calendar.MONTH); 400 } 401 402 /** 403 * Retrieves the seconds field of the current <code>Calendar</code>. 404 * 405 * @return the seconds field value 406 */ 407 public int getSecond() 408 { 409 return getSecond(localtime); 410 } 411 412 /** 413 * Retrieves the seconds field of the given <code>Calendar</code>. 414 * 415 * @param calendar 416 * the <code>Calendar</code> from which to get the field value 417 * @return the seconds field value 418 */ 419 public int getSecond(final Calendar calendar) 420 { 421 return get(calendar, Calendar.SECOND); 422 } 423 424 /** 425 * Retrieves the year field of the current <code>Calendar</code>. 426 * 427 * @return the year field value 428 */ 429 public int getYear() 430 { 431 return getYear(localtime); 432 } 433 434 /** 435 * Retrieves the year field of the given <code>Calendar</code>. 436 * 437 * @param calendar 438 * the <code>Calendar</code> from which to get the field value 439 * @return the year field value 440 */ 441 public int getYear(final Calendar calendar) 442 { 443 return get(calendar, Calendar.YEAR); 444 } 445 446 /** 447 * Subtracts the given <code>Duration</code> from this <code>Time</code> object, moving the time 448 * into the past. 449 * 450 * @param duration 451 * the <code>Duration</code> to subtract 452 * @return this duration of time 453 */ 454 public Time subtract(final Duration duration) 455 { 456 return millis(getMilliseconds() - duration.getMilliseconds()); 457 } 458 459 /** 460 * Subtract time from this and returns the difference as a <code>Duration</code> object. 461 * 462 * @param that 463 * the time to subtract 464 * @return the <code>Duration</code> between this and that time 465 */ 466 public Duration subtract(final Time that) 467 { 468 return Duration.milliseconds(getMilliseconds() - that.getMilliseconds()); 469 } 470 471 /** 472 * Retrieves a <code>Date</code> object for this <code>Time</code> object. A new 473 * <code>Date</code> object is always returned rather than attempting to cache a date since 474 * <code>Date</code> is mutable. 475 * 476 * @return this immutable <code>Time</code> object as a mutable <code>java.util.Date</code> 477 * object 478 */ 479 public Date toDate() 480 { 481 return new Date(getMilliseconds()); 482 } 483 484 /** 485 * Converts this <code>Time</code> value to a date <code>String</code> using the date formatter 486 * 'yyyy.MM.dd'. 487 * 488 * @return the date string 489 */ 490 public String toDateString() 491 { 492 return toDateString(localtime); 493 } 494 495 /** 496 * Converts this <code>Time</code> value to a date <code>String</code> using the formatter 497 * 'yyyy.MM.dd'. 498 * 499 * @param calendar 500 * the <code>Calendar</code> to use in the conversion 501 * @return the date <code>String</code> 502 */ 503 public String toDateString(final Calendar calendar) 504 { 505 synchronized (dateFormat) 506 { 507 synchronized (calendar) 508 { 509 dateFormat.setCalendar(calendar); 510 511 return dateFormat.format(new Date(getMilliseconds())).toLowerCase(Locale.ROOT); 512 } 513 } 514 } 515 516 /** 517 * Converts this <code>Time</code> value to a <code>String</code> suitable for use in a file 518 * system name. 519 * 520 * @return this <code>Time</code> value as a formatted <code>String</code> 521 */ 522 @Override 523 public String toString() 524 { 525 return toDateString() + "-" + toTimeString(); 526 } 527 528 /** 529 * Converts this <code>Time</code> object to a <code>String</code> using the given 530 * <code>Calendar</code> and format. 531 * 532 * @param calendar 533 * the <code>Calendar</code> to use in the conversion 534 * @param format 535 * the format to use 536 * @return this <code>Time</code> value as a formatted <code>String</code> 537 */ 538 public String toString(final Calendar calendar, final String format) 539 { 540 final SimpleDateFormat dateTimeFormat = new SimpleDateFormat(format, Locale.ENGLISH); 541 dateTimeFormat.setCalendar(calendar == null ? localtime : calendar); 542 return dateTimeFormat.format(new Date(getMilliseconds())); 543 } 544 545 /** 546 * Converts this <code>Time</code> value to a <code>String</code> using the given format. 547 * 548 * @param format 549 * the format to use 550 * @return this <code>Time</code> value as a formatted string 551 */ 552 public String toString(final String format) 553 { 554 return toString(null, format); 555 } 556 557 /** 558 * Returns this time stamp in RFC1123 string format. Contrary to 559 * {@link java.text.SimpleDateFormat} this is thread-safe. Taken from the source code of jetty 560 * 7.3.0, credits + thanks to Greg Wilkins! 561 * 562 * @return timestamp string in RFC1123 format 563 */ 564 public String toRfc1123TimestampString() 565 { 566 final Calendar cal = GregorianCalendar.getInstance(GMT); 567 final StringBuilder buf = new StringBuilder(32); 568 569 cal.setTimeInMillis(getMilliseconds()); 570 571 int day_of_week = cal.get(Calendar.DAY_OF_WEEK); 572 int day_of_month = cal.get(Calendar.DAY_OF_MONTH); 573 int month = cal.get(Calendar.MONTH); 574 int year = cal.get(Calendar.YEAR); 575 int century = year / 100; 576 year = year % 100; 577 578 int hours = cal.get(Calendar.HOUR_OF_DAY); 579 int minutes = cal.get(Calendar.MINUTE); 580 int seconds = cal.get(Calendar.SECOND); 581 582 buf.append(DAYS[day_of_week]); 583 buf.append(','); 584 buf.append(' '); 585 appendTwoDigits(buf, day_of_month); 586 587 buf.append(' '); 588 buf.append(MONTHS[month]); 589 buf.append(' '); 590 appendTwoDigits(buf, century); 591 appendTwoDigits(buf, year); 592 593 buf.append(' '); 594 appendTwoDigits(buf, hours); 595 buf.append(':'); 596 appendTwoDigits(buf, minutes); 597 buf.append(':'); 598 appendTwoDigits(buf, seconds); 599 buf.append(" GMT"); 600 601 return buf.toString(); 602 } 603 604 /** 605 * helper method for {@link #toRfc1123TimestampString()} 606 * 607 * @param str 608 * @param number 609 */ 610 private static void appendTwoDigits(StringBuilder str, int number) 611 { 612 str.append((char)(number / 10 + '0')); 613 str.append((char)(number % 10 + '0')); 614 } 615}