1 /* 2 * Copyright 2001-2013 Stephen Colebourne 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.joda.time; 17 18 import org.joda.time.format.DateTimeFormat; 19 20 /** 21 * Exception thrown when attempting to create an instant or date-time that cannot exist. 22 * <p> 23 * Classes like {@code DateTime} only store valid date-times. 24 * One of the cases where validity is important is handling daylight savings time (DST). 25 * In many places DST is used, where the local clock moves forward by an hour in spring and back by an hour in autumn/fall. 26 * This means that in spring, there is a "gap" where a local time does not exist. 27 * <p> 28 * This exception refers to this gap, and it means that your application tried to create 29 * a date-time inside the gap - a time that did not exist. 30 * Since Joda-Time objects must be valid, this is not allowed. 31 * <p> 32 * Possible solutions may be as follows:<br /> 33 * Use <code>LocalDateTime</code>, as all local date-times are valid.<br /> 34 * When converting a <code>LocalDate</code> to a <code>DateTime</code>, then use <code>toDateTimeAsStartOfDay()</code> 35 * as this handles and manages any gaps.<br /> 36 * When parsing, use <code>parseLocalDateTime()</code> if the string being parsed has no time-zone. 37 * 38 * @author Stephen Colebourne 39 * @since 2.2 40 */ 41 public class IllegalInstantException extends IllegalArgumentException { 42 43 /** Serialization lock. */ 44 private static final long serialVersionUID = 2858712538216L; 45 46 47 /** 48 * Constructor. 49 * 50 * @param message the message 51 */ 52 public IllegalInstantException(String message) { 53 super(message); 54 } 55 56 /** 57 * Constructor. 58 * 59 * @param instantLocal the local instant 60 * @param zoneId the time-zone ID, may be null 61 */ 62 public IllegalInstantException(long instantLocal, String zoneId) { 63 super(createMessage(instantLocal, zoneId)); 64 } 65 66 private static String createMessage(long instantLocal, String zoneId) { 67 String localDateTime = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").print(new Instant(instantLocal)); 68 String zone = (zoneId != null ? " (" + zoneId + ")" : ""); 69 return "Illegal instant due to time zone offset transition (daylight savings time 'gap'): " + localDateTime + zone; 70 } 71 72 //----------------------------------------------------------------------- 73 /** 74 * Checks if the exception is, or has a cause, of {@code IllegalInstantException}. 75 * 76 * @param ex the exception to check 77 * @return true if an {@code IllegalInstantException} 78 */ 79 public static boolean isIllegalInstant(Throwable ex) { 80 if (ex instanceof IllegalInstantException) { 81 return true; 82 } 83 while (ex.getCause() != null && ex.getCause() != ex) { 84 return isIllegalInstant(ex.getCause()); 85 } 86 return false; 87 } 88 89 }