1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 /* 5 ****************************************************************************** 6 * Copyright (C) 2007-2011, International Business Machines Corporation and * 7 * others. All Rights Reserved. * 8 ****************************************************************************** 9 */ 10 11 package ohos.global.icu.impl.duration; 12 13 import java.util.TimeZone; 14 15 import ohos.global.icu.impl.duration.impl.DataRecord; 16 import ohos.global.icu.impl.duration.impl.PeriodFormatterData; 17 import ohos.global.icu.impl.duration.impl.PeriodFormatterDataService; 18 19 /** 20 * Default implementation of PeriodBuilderFactory. This creates builders that 21 * use approximate durations. 22 */ 23 class BasicPeriodBuilderFactory implements PeriodBuilderFactory { 24 private PeriodFormatterDataService ds; 25 private Settings settings; 26 27 private static final short allBits = 0xff; 28 BasicPeriodBuilderFactory(PeriodFormatterDataService ds)29 BasicPeriodBuilderFactory(PeriodFormatterDataService ds) { 30 this.ds = ds; 31 this.settings = new Settings(); 32 } 33 approximateDurationOf(TimeUnit unit)34 static long approximateDurationOf(TimeUnit unit) { 35 return TimeUnit.approxDurations[unit.ordinal]; 36 } 37 38 class Settings { 39 boolean inUse; 40 short uset = allBits; 41 TimeUnit maxUnit = TimeUnit.YEAR; 42 TimeUnit minUnit = TimeUnit.MILLISECOND; 43 int maxLimit; 44 int minLimit; 45 boolean allowZero = true; 46 boolean weeksAloneOnly; 47 boolean allowMillis = true; 48 setUnits(int uset)49 Settings setUnits(int uset) { 50 if (this.uset == uset) { 51 return this; 52 } 53 Settings result = inUse ? copy() : this; 54 55 result.uset = (short)uset; 56 57 if ((uset & allBits) == allBits) { 58 result.uset = allBits; 59 result.maxUnit = TimeUnit.YEAR; 60 result.minUnit = TimeUnit.MILLISECOND; 61 } else { 62 int lastUnit = -1; 63 for (int i = 0; i < TimeUnit.units.length; ++i) { 64 if (0 != (uset & (1 << i))) { 65 if (lastUnit == -1) { 66 result.maxUnit = TimeUnit.units[i]; 67 } 68 lastUnit = i; 69 } 70 } 71 if (lastUnit == -1) { 72 // currently empty, but this might be transient so no fail 73 result.minUnit = result.maxUnit = null; 74 } else { 75 result.minUnit = TimeUnit.units[lastUnit]; 76 } 77 } 78 79 return result; 80 } 81 effectiveSet()82 short effectiveSet() { 83 if (allowMillis) { 84 return uset; 85 } 86 return (short)(uset & ~(1 << TimeUnit.MILLISECOND.ordinal)); 87 } 88 effectiveMinUnit()89 TimeUnit effectiveMinUnit() { 90 if (allowMillis || minUnit != TimeUnit.MILLISECOND) { 91 return minUnit; 92 } 93 // -1 to skip millisecond 94 for (int i = TimeUnit.units.length - 1; --i >= 0;) { 95 if (0 != (uset & (1 << i))) { 96 return TimeUnit.units[i]; 97 } 98 } 99 return TimeUnit.SECOND; // default for pathological case 100 } 101 setMaxLimit(float maxLimit)102 Settings setMaxLimit(float maxLimit) { 103 int val = maxLimit <= 0 ? 0 : (int)(maxLimit*1000); 104 if (maxLimit == val) { 105 return this; 106 } 107 Settings result = inUse ? copy() : this; 108 result.maxLimit = val; 109 return result; 110 } 111 setMinLimit(float minLimit)112 Settings setMinLimit(float minLimit) { 113 int val = minLimit <= 0 ? 0 : (int)(minLimit*1000); 114 if (minLimit == val) { 115 return this; 116 } 117 Settings result = inUse ? copy() : this; 118 result.minLimit = val; 119 return result; 120 } 121 setAllowZero(boolean allow)122 Settings setAllowZero(boolean allow) { 123 if (this.allowZero == allow) { 124 return this; 125 } 126 Settings result = inUse ? copy() : this; 127 result.allowZero = allow; 128 return result; 129 } 130 setWeeksAloneOnly(boolean weeksAlone)131 Settings setWeeksAloneOnly(boolean weeksAlone) { 132 if (this.weeksAloneOnly == weeksAlone) { 133 return this; 134 } 135 Settings result = inUse ? copy() : this; 136 result.weeksAloneOnly = weeksAlone; 137 return result; 138 } 139 setAllowMilliseconds(boolean allowMillis)140 Settings setAllowMilliseconds(boolean allowMillis) { 141 if (this.allowMillis == allowMillis) { 142 return this; 143 } 144 Settings result = inUse ? copy() : this; 145 result.allowMillis = allowMillis; 146 return result; 147 } 148 setLocale(String localeName)149 Settings setLocale(String localeName) { 150 PeriodFormatterData data = ds.get(localeName); 151 return this 152 .setAllowZero(data.allowZero()) 153 .setWeeksAloneOnly(data.weeksAloneOnly()) 154 .setAllowMilliseconds(data.useMilliseconds() != DataRecord.EMilliSupport.NO); 155 } 156 setInUse()157 Settings setInUse() { 158 inUse = true; 159 return this; 160 } 161 createLimited(long duration, boolean inPast)162 Period createLimited(long duration, boolean inPast) { 163 if (maxLimit > 0) { 164 long maxUnitDuration = approximateDurationOf(maxUnit); 165 if (duration * 1000 > maxLimit * maxUnitDuration) { 166 return Period.moreThan(maxLimit/1000f, maxUnit).inPast(inPast); 167 } 168 } 169 170 if (minLimit > 0) { 171 TimeUnit emu = effectiveMinUnit(); 172 long emud = approximateDurationOf(emu); 173 long eml = (emu == minUnit) ? minLimit : 174 Math.max(1000, (approximateDurationOf(minUnit) * minLimit) / emud); 175 if (duration * 1000 < eml * emud) { 176 return Period.lessThan(eml/1000f, emu).inPast(inPast); 177 } 178 } 179 return null; 180 } 181 copy()182 public Settings copy() { 183 Settings result = new Settings(); 184 result.inUse = inUse; 185 result.uset = uset; 186 result.maxUnit = maxUnit; 187 result.minUnit = minUnit; 188 result.maxLimit = maxLimit; 189 result.minLimit = minLimit; 190 result.allowZero = allowZero; 191 result.weeksAloneOnly = weeksAloneOnly; 192 result.allowMillis = allowMillis; 193 return result; 194 } 195 } 196 197 @Override setAvailableUnitRange(TimeUnit minUnit, TimeUnit maxUnit)198 public PeriodBuilderFactory setAvailableUnitRange(TimeUnit minUnit, 199 TimeUnit maxUnit) { 200 int uset = 0; 201 for (int i = maxUnit.ordinal; i <= minUnit.ordinal; ++i) { 202 uset |= 1 << i; 203 } 204 if (uset == 0) { 205 throw new IllegalArgumentException("range " + minUnit + " to " + maxUnit + " is empty"); 206 } 207 settings = settings.setUnits(uset); 208 return this; 209 } 210 211 @Override setUnitIsAvailable(TimeUnit unit, boolean available)212 public PeriodBuilderFactory setUnitIsAvailable(TimeUnit unit, 213 boolean available) { 214 int uset = settings.uset; 215 if (available) { 216 uset |= 1 << unit.ordinal; 217 } else { 218 uset &= ~(1 << unit.ordinal); 219 } 220 settings = settings.setUnits(uset); 221 return this; 222 } 223 224 @Override setMaxLimit(float maxLimit)225 public PeriodBuilderFactory setMaxLimit(float maxLimit) { 226 settings = settings.setMaxLimit(maxLimit); 227 return this; 228 } 229 230 @Override setMinLimit(float minLimit)231 public PeriodBuilderFactory setMinLimit(float minLimit) { 232 settings = settings.setMinLimit(minLimit); 233 return this; 234 } 235 236 @Override setAllowZero(boolean allow)237 public PeriodBuilderFactory setAllowZero(boolean allow) { 238 settings = settings.setAllowZero(allow); 239 return this; 240 } 241 242 @Override setWeeksAloneOnly(boolean aloneOnly)243 public PeriodBuilderFactory setWeeksAloneOnly(boolean aloneOnly) { 244 settings = settings.setWeeksAloneOnly(aloneOnly); 245 return this; 246 } 247 248 @Override setAllowMilliseconds(boolean allow)249 public PeriodBuilderFactory setAllowMilliseconds(boolean allow) { 250 settings = settings.setAllowMilliseconds(allow); 251 return this; 252 } 253 254 @Override setLocale(String localeName)255 public PeriodBuilderFactory setLocale(String localeName) { 256 settings = settings.setLocale(localeName); 257 return this; 258 } 259 260 @Override setTimeZone(TimeZone timeZone)261 public PeriodBuilderFactory setTimeZone(TimeZone timeZone) { 262 // ignore this 263 return this; 264 } 265 getSettings()266 private Settings getSettings() { 267 if (settings.effectiveSet() == 0) { 268 return null; 269 } 270 return settings.setInUse(); 271 } 272 273 /** 274 * Return a builder that represents relative time in terms of the single 275 * given TimeUnit 276 * 277 * @param unit the single TimeUnit with which to represent times 278 * @return a builder 279 */ 280 @Override getFixedUnitBuilder(TimeUnit unit)281 public PeriodBuilder getFixedUnitBuilder(TimeUnit unit) { 282 return FixedUnitBuilder.get(unit, getSettings()); 283 } 284 285 /** 286 * Return a builder that represents relative time in terms of the 287 * largest period less than or equal to the duration. 288 * 289 * @return a builder 290 */ 291 @Override getSingleUnitBuilder()292 public PeriodBuilder getSingleUnitBuilder() { 293 return SingleUnitBuilder.get(getSettings()); 294 } 295 296 /** 297 * Return a builder that formats the largest one or two periods, 298 * Starting with the largest period less than or equal to the duration. 299 * It formats two periods if the first period has a count < 2 300 * and the next period has a count >= 1. 301 * 302 * @return a builder 303 */ 304 @Override getOneOrTwoUnitBuilder()305 public PeriodBuilder getOneOrTwoUnitBuilder() { 306 return OneOrTwoUnitBuilder.get(getSettings()); 307 } 308 309 /** 310 * Return a builder that formats the given number of periods, 311 * starting with the largest period less than or equal to the 312 * duration. 313 * 314 * @return a builder 315 */ 316 @Override getMultiUnitBuilder(int periodCount)317 public PeriodBuilder getMultiUnitBuilder(int periodCount) { 318 return MultiUnitBuilder.get(periodCount, getSettings()); 319 } 320 } 321 322 abstract class PeriodBuilderImpl implements PeriodBuilder { 323 324 protected BasicPeriodBuilderFactory.Settings settings; 325 326 @Override create(long duration)327 public Period create(long duration) { 328 return createWithReferenceDate(duration, System.currentTimeMillis()); 329 } 330 approximateDurationOf(TimeUnit unit)331 public long approximateDurationOf(TimeUnit unit) { 332 return BasicPeriodBuilderFactory.approximateDurationOf(unit); 333 } 334 335 @Override createWithReferenceDate(long duration, long referenceDate)336 public Period createWithReferenceDate(long duration, long referenceDate) { 337 boolean inPast = duration < 0; 338 if (inPast) { 339 duration = -duration; 340 } 341 Period ts = settings.createLimited(duration, inPast); 342 if (ts == null) { 343 ts = handleCreate(duration, referenceDate, inPast); 344 if (ts == null) { 345 ts = Period.lessThan(1, settings.effectiveMinUnit()).inPast(inPast); 346 } 347 } 348 return ts; 349 } 350 351 @Override 352 public PeriodBuilder withTimeZone(TimeZone timeZone) { 353 // ignore the time zone 354 return this; 355 } 356 357 @Override 358 public PeriodBuilder withLocale(String localeName) { 359 BasicPeriodBuilderFactory.Settings newSettings = settings.setLocale(localeName); 360 if (newSettings != settings) { 361 return withSettings(newSettings); 362 } 363 return this; 364 } 365 366 protected abstract PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse); 367 368 protected abstract Period handleCreate(long duration, long referenceDate, 369 boolean inPast); 370 371 protected PeriodBuilderImpl(BasicPeriodBuilderFactory.Settings settings) { 372 this.settings = settings; 373 } 374 } 375 376 class FixedUnitBuilder extends PeriodBuilderImpl { 377 private TimeUnit unit; 378 379 public static FixedUnitBuilder get(TimeUnit unit, BasicPeriodBuilderFactory.Settings settingsToUse) { 380 if (settingsToUse != null && (settingsToUse.effectiveSet() & (1 << unit.ordinal)) != 0) { 381 return new FixedUnitBuilder(unit, settingsToUse); 382 } 383 return null; 384 } 385 386 FixedUnitBuilder(TimeUnit unit, BasicPeriodBuilderFactory.Settings settings) { 387 super(settings); 388 this.unit = unit; 389 } 390 391 @Override 392 protected PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse) { 393 return get(unit, settingsToUse); 394 } 395 396 @Override 397 protected Period handleCreate(long duration, long referenceDate, 398 boolean inPast) { 399 if (unit == null) { 400 return null; 401 } 402 long unitDuration = approximateDurationOf(unit); 403 return Period.at((float)((double)duration/unitDuration), unit) 404 .inPast(inPast); 405 } 406 } 407 408 class SingleUnitBuilder extends PeriodBuilderImpl { 409 SingleUnitBuilder(BasicPeriodBuilderFactory.Settings settings) { 410 super(settings); 411 } 412 413 public static SingleUnitBuilder get(BasicPeriodBuilderFactory.Settings settings) { 414 if (settings == null) { 415 return null; 416 } 417 return new SingleUnitBuilder(settings); 418 } 419 420 @Override 421 protected PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse) { 422 return SingleUnitBuilder.get(settingsToUse); 423 } 424 425 @Override 426 protected Period handleCreate(long duration, long referenceDate, 427 boolean inPast) { 428 short uset = settings.effectiveSet(); 429 for (int i = 0; i < TimeUnit.units.length; ++i) { 430 if (0 != (uset & (1 << i))) { 431 TimeUnit unit = TimeUnit.units[i]; 432 long unitDuration = approximateDurationOf(unit); 433 if (duration >= unitDuration) { 434 return Period.at((float)((double)duration/unitDuration), unit) 435 .inPast(inPast); 436 } 437 } 438 } 439 return null; 440 } 441 } 442 443 class OneOrTwoUnitBuilder extends PeriodBuilderImpl { 444 OneOrTwoUnitBuilder(BasicPeriodBuilderFactory.Settings settings) { 445 super(settings); 446 } 447 448 public static OneOrTwoUnitBuilder get(BasicPeriodBuilderFactory.Settings settings) { 449 if (settings == null) { 450 return null; 451 } 452 return new OneOrTwoUnitBuilder(settings); 453 } 454 455 @Override 456 protected PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse) { 457 return OneOrTwoUnitBuilder.get(settingsToUse); 458 } 459 460 @Override 461 protected Period handleCreate(long duration, long referenceDate, 462 boolean inPast) { 463 Period period = null; 464 short uset = settings.effectiveSet(); 465 for (int i = 0; i < TimeUnit.units.length; ++i) { 466 if (0 != (uset & (1 << i))) { 467 TimeUnit unit = TimeUnit.units[i]; 468 long unitDuration = approximateDurationOf(unit); 469 if (duration >= unitDuration || period != null) { 470 double count = (double)duration/unitDuration; 471 if (period == null) { 472 if (count >= 2) { 473 period = Period.at((float)count, unit); 474 break; 475 } 476 period = Period.at(1, unit).inPast(inPast); 477 duration -= unitDuration; 478 } else { 479 if (count >= 1) { 480 period = period.and((float)count, unit); 481 } 482 break; 483 } 484 } 485 } 486 } 487 return period; 488 } 489 } 490 491 class MultiUnitBuilder extends PeriodBuilderImpl { 492 private int nPeriods; 493 494 MultiUnitBuilder(int nPeriods, BasicPeriodBuilderFactory.Settings settings) { 495 super(settings); 496 this.nPeriods = nPeriods; 497 } 498 499 public static MultiUnitBuilder get(int nPeriods, BasicPeriodBuilderFactory.Settings settings) { 500 if (nPeriods > 0 && settings != null) { 501 return new MultiUnitBuilder(nPeriods, settings); 502 } 503 return null; 504 } 505 506 @Override 507 protected PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse) { 508 return MultiUnitBuilder.get(nPeriods, settingsToUse); 509 } 510 511 @Override 512 protected Period handleCreate(long duration, long referenceDate, 513 boolean inPast) { 514 Period period = null; 515 int n = 0; 516 short uset = settings.effectiveSet(); 517 for (int i = 0; i < TimeUnit.units.length; ++i) { 518 if (0 != (uset & (1 << i))) { 519 TimeUnit unit = TimeUnit.units[i]; 520 if (n == nPeriods) { 521 break; 522 } 523 long unitDuration = approximateDurationOf(unit); 524 if (duration >= unitDuration || n > 0) { 525 ++n; 526 double count = (double)duration / unitDuration; 527 if (n < nPeriods) { 528 count = Math.floor(count); 529 duration -= (long)(count * unitDuration); 530 } 531 if (period == null) { 532 period = Period.at((float)count, unit).inPast(inPast); 533 } else { 534 period = period.and((float)count, unit); 535 } 536 } 537 } 538 } 539 return period; 540 } 541 } 542 543