1 /* 2 (C) Copyright IBM Corp. 2006, 2013 3 4 THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE 5 ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE 6 CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT. 7 8 You can obtain a current copy of the Eclipse Public License from 9 http://www.opensource.org/licenses/eclipse-1.0.php 10 11 @author : Endre Bak, ebak@de.ibm.com 12 * 13 * Flag Date Prog Description 14 * ------------------------------------------------------------------------------- 15 * 1565892 2006-10-06 ebak Make SBLIM client JSR48 compliant 16 * 1678807 2007-03-12 ebak Minor CIMDateTime suggestions 17 * 1931621 2008-04-02 blaschke-oss CIMDateTimeAbsolute(Calendar) does not respect DST 18 * 2003590 2008-06-30 blaschke-oss Change licensing from CPL to EPL 19 * 2524131 2009-01-21 raman_arora Upgrade client to JDK 1.5 (Phase 1) 20 * 2531371 2009-02-10 raman_arora Upgrade client to JDK 1.5 (Phase 2) 21 * 2750520 2009-04-10 blaschke-oss Code cleanup from empty statement et al 22 * 2795671 2009-05-22 raman_arora Add Type to Comparable <T> 23 * 2806362 2009-06-14 blaschke-oss Missing new CIMDateTimeAbsolute.getUTCOffset() method 24 * 2935258 2010-01-22 blaschke-oss Sync up javax.cim.* javadoc with JSR48 1.0.0 25 * 2944826 2010-02-08 blaschke-oss getUTCOffset() incorrect if not significant field 26 * 2973300 2010-03-19 blaschke-oss TCK: CIMDateTimeXXX.compareTo() does not handle null 27 * 3022501 2010-06-30 blaschke-oss Possible integer overflow in getTotalUSec 28 * 3400209 2011-08-31 blaschke-oss Highlighted Static Analysis (PMD) issues 29 * 3565581 2012-09-07 blaschke-oss TCK: remove unnecessary overriding methods 30 * 2674 2013-09-26 blaschke-oss Null pointer exception in CIMDateTime(String) 31 * 2716 2013-12-11 blaschke-oss Sync up javax.* javadoc with JSR48 1.0.0 Final V 32 */ 33 34 package org.metricshub.wbem.javax.cim; 35 36 /*- 37 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲ 38 * WBEM Java Client 39 * ჻჻჻჻჻჻ 40 * Copyright 2023 - 2025 MetricsHub 41 * ჻჻჻჻჻჻ 42 * Licensed under the Apache License, Version 2.0 (the "License"); 43 * you may not use this file except in compliance with the License. 44 * You may obtain a copy of the License at 45 * 46 * http://www.apache.org/licenses/LICENSE-2.0 47 * 48 * Unless required by applicable law or agreed to in writing, software 49 * distributed under the License is distributed on an "AS IS" BASIS, 50 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 51 * See the License for the specific language governing permissions and 52 * limitations under the License. 53 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱ 54 */ 55 56 import java.util.Calendar; 57 import org.metricshub.wbem.sblim.cimclient.internal.cim.DTStringReader; 58 import org.metricshub.wbem.sblim.cimclient.internal.cim.DTStringWriter; 59 60 //Sync'd against JSR48 1.0.0 javadoc (version 1.7.0_03) on Tue Dec 10 07:02:50 EST 2013 61 /** 62 * This class represents the datetime data type when used as a time value as 63 * specified in the CIM Infrastructure specification. It is in the format 64 * yyyyMMddHHmmss.SSSSSSsutc where: 65 * <ul> 66 * <li>yyyy - is a 4 digit year</li> 67 * <li>MM - is the month</li> 68 * <li>dd - is the day of the month</li> 69 * <li>HH - is the hour (24 hour clock)</li> 70 * <li>mm - is the minute</li> 71 * <li>ss - is the second</li> 72 * <li>SSSSSS - is the number of microseconds</li> 73 * <li>s - is "+" or "-", indicating the sign of the UTC (Universal Coordinated 74 * Time; for all intents and purposes the same as Greenwich Mean Time)</li> 75 * <li>utc - is the offset from UTC in minutes (using the sign indicated by s).</li> 76 * </ul> 77 * For example Monday, May 25, 1998, at 1:30 PM EST would be represented as: 78 * 19980525133015.000000-300. Values must be zero-padded so that the entire 79 * string is always the same 25-character length. Fields which are not 80 * significant must be replaced with asterisk characters. 81 */ 82 public class CIMDateTimeAbsolute extends CIMDateTime { 83 private static final long serialVersionUID = 7556792806296945178l; 84 85 private int iYear, iMonth, iDay, iHour, iMin, iSec, iUSec, iUtc; 86 87 private boolean iUnsignificantUtc; 88 89 private String iStr; 90 91 /** 92 * Create a <code>CIMDateTimeAbsolute</code> object using the current 93 * Time/Date of the system. 94 */ 95 public CIMDateTimeAbsolute() { 96 set(Calendar.getInstance()); 97 } 98 99 /** 100 * Create a <code>CIMDateTimeAbsolute</code> object using a 101 * <code>Calendar</code> object. 102 * 103 * @param pCalendar 104 * A <code>Calendar</code> object used to initialize this object. 105 * @throws IllegalArgumentException 106 * If <code>Calendar</code> object is <code>null</code>. 107 */ 108 public CIMDateTimeAbsolute(Calendar pCalendar) throws IllegalArgumentException { 109 if (pCalendar == null) throw new IllegalArgumentException("Null Calendar is not allowed!"); 110 if (pCalendar.get(Calendar.YEAR) > 9999) throw new IllegalArgumentException( 111 "The year field cannot be greater than 9999!" 112 ); 113 set(pCalendar); 114 } 115 116 /** 117 * Creates a <code>CIMDateTimeAbsolute</code> object using a string. 118 * 119 * @param pDateTime 120 * A string in the format of yyyyMMddHHmmss.SSSSSSsutc. 121 * @throws IllegalArgumentException 122 * If string is not in the correct format or <code>null</code>. 123 */ 124 public CIMDateTimeAbsolute(String pDateTime) throws IllegalArgumentException { 125 if (pDateTime == null) throw new IllegalArgumentException("Null DateTime is not allowed!"); 126 DTStringReader reader = new DTStringReader(pDateTime); 127 this.iYear = reader.readAndCheck(4, "year", 0, 9999, true); 128 this.iMonth = reader.readAndCheck(2, "month", 1, 12, true); 129 this.iDay = reader.readAndCheck(2, "day", 1, 31, true); 130 this.iHour = reader.readAndCheck(2, "hour", 0, 23, true); 131 this.iMin = reader.readAndCheck(2, "minute", 0, 59, true); 132 this.iSec = reader.readAndCheck(2, "second", 0, 59, true); 133 reader.read('.'); 134 this.iUSec = reader.readAndCheck(6, "microSeconds", 0, 999999, true); 135 char sign = reader.read(); 136 if (sign != '+' && sign != '-') { 137 String msg = "Illegal character '" + sign + "' at position " + reader.getPos() + "! '+' or '-' is expected."; 138 throw new IllegalArgumentException(msg); 139 } 140 this.iUtc = reader.read(3, "utc", true); 141 if (reader.isUnsignificant()) { 142 this.iUnsignificantUtc = true; 143 } else if (sign == '-') { 144 this.iUtc = -this.iUtc; 145 } 146 if (reader.read() != 0) throw new IllegalArgumentException("Extra character at the end of " + pDateTime + " !"); 147 this.iStr = pDateTime; 148 } 149 150 /** 151 * Compares the <code>CIMDateTimeAbsolute</code> object with this one. If 152 * either date has "Not Significant" fields then we can only compare the 153 * significant fields. 154 * 155 * @param pDateTime 156 * The <code>CIMDateTimeAbsolute</code> to be compared with this 157 * one. 158 * @return -1, zero, or 1 as this date is less than, equal to, or greater 159 * than the specified date. 160 * @throws IllegalArgumentException 161 * If the object passed in is not an instance of 162 * <code>CIMDataTimeAbsolute</code>. 163 */ 164 public int compareTo(CIMDateTime pDateTime) throws IllegalArgumentException { 165 if (!(pDateTime instanceof CIMDateTimeAbsolute)) { 166 String msg = 167 "pDateTime must be a CIMDateTimeAbsolute instance while it is a " + 168 (pDateTime == null ? "null!" : pDateTime.getClass().getName() + " instance!"); 169 throw new IllegalArgumentException(msg); 170 } 171 172 CIMDateTimeAbsolute that = (CIMDateTimeAbsolute) pDateTime; 173 /* 174 * Comparison: 1. building Calendars from both dates. If a field is not 175 * significant it and it's corresponding pair is cleared. 176 */ 177 int mask = getMask() & that.getMask(); 178 long thisMicros = getTotalUSec(mask); 179 long thatMicros = that.getTotalUSec(mask); 180 long val = thisMicros - thatMicros; 181 if (val == 0) return 0; 182 return val < 0 ? -1 : 1; 183 } 184 185 /** 186 * Gets the internal string representation of the date/time object. 187 * 188 * @return The internal representation of the date/time object. 189 */ 190 @Override 191 public String getDateTimeString() { 192 if (this.iStr != null) return this.iStr; 193 // yyyyMMddHHmmss.uuuuuuSutc 194 DTStringWriter dTWriter = new DTStringWriter(); 195 dTWriter.write(4, this.iYear); 196 dTWriter.write(2, this.iMonth); 197 dTWriter.write(2, this.iDay); 198 dTWriter.write(2, this.iHour); 199 dTWriter.write(2, this.iMin); 200 dTWriter.write(2, this.iSec); 201 dTWriter.write('.'); 202 dTWriter.write(6, this.iUSec); 203 if (this.iUnsignificantUtc) dTWriter.write("+***"); else dTWriter.writeSigned(3, this.iUtc); 204 return this.iStr = dTWriter.toString(); 205 } 206 207 /** 208 * Returns day value of this date. 209 * 210 * @return If day field "not significant" this returns -1, otherwise returns 211 * day of this date. 212 */ 213 public int getDay() { 214 return this.iDay; 215 } 216 217 /** 218 * Returns hour value of this date. 219 * 220 * @return If hour field "not significant" this returns -1, otherwise 221 * returns hour of this date. 222 */ 223 public int getHour() { 224 return this.iHour; 225 } 226 227 /** 228 * Returns microsecond value of this date. 229 * 230 * @return If microsecond field "not significant" this returns -1, otherwise 231 * returns microseconds of this date. 232 */ 233 public int getMicrosecond() { 234 return this.iUSec; 235 } 236 237 /** 238 * Returns minute value of this date. 239 * 240 * @return If minute field "not significant" this returns -1, otherwise 241 * returns minute of this date. 242 */ 243 public int getMinute() { 244 return this.iMin; 245 } 246 247 /** 248 * Returns month value of this date. 249 * 250 * @return If month field "not significant" this returns -1, otherwise 251 * returns the month of this date. 252 */ 253 public int getMonth() { 254 return this.iMonth; 255 } 256 257 /** 258 * Returns second value of this date. 259 * 260 * @return If second field "not significant" this returns -1, otherwise 261 * returns second of this date. 262 */ 263 public int getSecond() { 264 return this.iSec; 265 } 266 267 /** 268 * Returns UTC offset value of this date. 269 * 270 * @return UTC offset of this date. 271 */ 272 public int getUTCOffset() { 273 return this.iUnsignificantUtc ? -1 : this.iUtc; 274 } 275 276 /** 277 * Returns year value of this Date. 278 * 279 * @return If year field "not significant" this returns -1, otherwise 280 * returns the year of this date. 281 */ 282 public int getYear() { 283 return this.iYear; 284 } 285 286 /** 287 * Returns the hash code for this object. 288 * 289 * @return A hash code value for this object. 290 * @see java.lang.Object#hashCode() 291 */ 292 @Override 293 public int hashCode() { 294 return getDateTimeString().hashCode(); 295 } 296 297 /** 298 * Returns a <code>String</code> representation of the 299 * <code>CIMDateTimeAbsolute</code>. This method is intended to be used only 300 * for debugging purposes, and the format of the returned string may vary 301 * between implementations. The returned string may be empty but may not be 302 * <code>null</code>. 303 * 304 * @return String representation of this datetime. 305 */ 306 @Override 307 public String toString() { 308 return getDateTimeString(); 309 } 310 311 private static final int YEAR = 1, MONTH = 2, DAY = 4, HOUR = 8, MIN = 16, SEC = 32, USEC = 64, UTC = 128; 312 313 /** 314 * Get mask of this <code>CIMDateTimeAbsolute</code> where bit is set if the 315 * corresponding field is significant or clear if it is not significant. 316 * 317 * @return Mask of significant fields in datetime object. 318 */ 319 private int getMask() { 320 int mask = 0; 321 if (this.iYear != -1) mask |= YEAR; 322 if (this.iMonth != -1) mask |= MONTH; 323 if (this.iDay != -1) mask |= DAY; 324 if (this.iHour != -1) mask |= HOUR; 325 if (this.iMin != -1) mask |= MIN; 326 if (this.iSec != -1) mask |= SEC; 327 if (this.iUSec != -1) mask |= USEC; 328 if (!this.iUnsignificantUtc) mask |= UTC; 329 return mask; 330 } 331 332 /** 333 * Get value of a field based on mask. 334 * 335 * @param pMask 336 * Mask of significant fields. 337 * @param pField 338 * Field. 339 * @param pValue 340 * Value of field. 341 * @param pInitValue 342 * Initial value of field. 343 * @return Value of field if field significant, otherwise initial value. 344 */ 345 private int mask(int pMask, int pField, int pValue, int pInitValue) { 346 return ((pMask & pField) > 0) ? pValue : pInitValue; 347 } 348 349 /** 350 * Get total microseconds of <code>CIMDateTimeAbsolute</code> object where 351 * only significant fields are used in calculation. 352 * 353 * @param pMask 354 * Mask of significant fields. 355 * @return Total microseconds of significant fields in datetime. 356 */ 357 private long getTotalUSec(int pMask) { 358 Calendar cal = Calendar.getInstance(); 359 cal.set(Calendar.YEAR, mask(pMask, YEAR, this.iYear, 0)); 360 cal.set(Calendar.MONTH, mask(pMask, MONTH, this.iMonth - 1, 0)); 361 cal.set(Calendar.DAY_OF_MONTH, mask(pMask, DAY, this.iDay, 1)); 362 cal.set(Calendar.HOUR_OF_DAY, mask(pMask, HOUR, this.iHour, 0)); 363 cal.set(Calendar.MINUTE, mask(pMask, MIN, this.iMin, 0)); 364 cal.set(Calendar.SECOND, mask(pMask, SEC, this.iSec, 0)); 365 int millis = this.iUSec / 1000, micros = this.iUSec % 1000; 366 cal.set(Calendar.MILLISECOND, mask(pMask, USEC, millis, 0)); 367 long totalMicros = cal.getTimeInMillis() * 1000; 368 if ((pMask & USEC) > 0) totalMicros += micros; 369 /* 370 * UTC is added to the calculated micros 371 */ 372 if ((pMask & UTC) > 0) totalMicros += this.iUtc * 60000000L; 373 return totalMicros; 374 } 375 376 /** 377 * Initializes this <code>CIMDateTimeAbsolute</code> object from the 378 * <code>Calendar</code> passed in. 379 * 380 * @param pCal 381 * Calendar object. 382 */ 383 private void set(Calendar pCal) { 384 this.iYear = pCal.get(Calendar.YEAR); 385 this.iMonth = pCal.get(Calendar.MONTH) + 1; 386 this.iDay = pCal.get(Calendar.DAY_OF_MONTH); 387 this.iHour = pCal.get(Calendar.HOUR_OF_DAY); 388 this.iMin = pCal.get(Calendar.MINUTE); 389 this.iSec = pCal.get(Calendar.SECOND); 390 this.iUSec = pCal.get(Calendar.MILLISECOND) * 1000; 391 if (pCal.getTimeZone().inDaylightTime(pCal.getTime())) { 392 this.iUtc = (pCal.get(Calendar.ZONE_OFFSET) + pCal.get(Calendar.DST_OFFSET)) / 60000; 393 } else { 394 this.iUtc = pCal.get(Calendar.ZONE_OFFSET) / 60000; 395 } 396 } 397 }