1 /******************************************************************************* 2 3 copyright: Copyright (c) 2005 John Chapman. All rights reserved 4 5 license: BSD style: $(LICENSE) 6 7 version: Initial release: 2005 8 9 author: John Chapman 10 11 Contains classes that provide information about locales, such as 12 the language and calendars, as well as cultural conventions used 13 for formatting dates, currency and numbers. Use these classes when 14 writing applications for an international audience. 15 16 ******************************************************************************/ 17 18 /** 19 * $(MEMBERTABLE 20 * $(TR 21 * $(TH Interface) 22 * $(TH Description) 23 * ) 24 * $(TR 25 * $(TD $(LINK2 #IFormatService, IFormatService)) 26 * $(TD Retrieves an object to control formatting.) 27 * ) 28 * ) 29 * 30 * $(MEMBERTABLE 31 * $(TR 32 * $(TH Class) 33 * $(TH Description) 34 * ) 35 * $(TR 36 * $(TD $(LINK2 #Calendar, Calendar)) 37 * $(TD Represents time in week, month and year divisions.) 38 * ) 39 * $(TR 40 * $(TD $(LINK2 #Culture, Culture)) 41 * $(TD Provides information about a culture, such as its name, calendar and date and number format patterns.) 42 * ) 43 * $(TR 44 * $(TD $(LINK2 #DateTimeFormat, DateTimeFormat)) 45 * $(TD Determines how $(LINK2 #Time, Time) values are formatted, depending on the culture.) 46 * ) 47 * $(TR 48 * $(TD $(LINK2 #DaylightSavingTime, DaylightSavingTime)) 49 * $(TD Represents a period of daylight-saving time.) 50 * ) 51 * $(TR 52 * $(TD $(LINK2 #Gregorian, Gregorian)) 53 * $(TD Represents the Gregorian calendar.) 54 * ) 55 * $(TR 56 * $(TD $(LINK2 #Hebrew, Hebrew)) 57 * $(TD Represents the Hebrew calendar.) 58 * ) 59 * $(TR 60 * $(TD $(LINK2 #Hijri, Hijri)) 61 * $(TD Represents the Hijri calendar.) 62 * ) 63 * $(TR 64 * $(TD $(LINK2 #Japanese, Japanese)) 65 * $(TD Represents the Japanese calendar.) 66 * ) 67 * $(TR 68 * $(TD $(LINK2 #Korean, Korean)) 69 * $(TD Represents the Korean calendar.) 70 * ) 71 * $(TR 72 * $(TD $(LINK2 #NumberFormat, NumberFormat)) 73 * $(TD Determines how numbers are formatted, according to the current culture.) 74 * ) 75 * $(TR 76 * $(TD $(LINK2 #Region, Region)) 77 * $(TD Provides information about a region.) 78 * ) 79 * $(TR 80 * $(TD $(LINK2 #Taiwan, Taiwan)) 81 * $(TD Represents the Taiwan calendar.) 82 * ) 83 * $(TR 84 * $(TD $(LINK2 #ThaiBuddhist, ThaiBuddhist)) 85 * $(TD Represents the Thai Buddhist calendar.) 86 * ) 87 * ) 88 * 89 * $(MEMBERTABLE 90 * $(TR 91 * $(TH Struct) 92 * $(TH Description) 93 * ) 94 * $(TR 95 * $(TD $(LINK2 #Time, Time)) 96 * $(TD Represents time expressed as a date and time of day.) 97 * ) 98 * $(TR 99 * $(TD $(LINK2 #TimeSpan, TimeSpan)) 100 * $(TD Represents a time interval.) 101 * ) 102 * ) 103 */ 104 105 module tango.text.locale.Core; 106 107 private import tango.core.Exception; 108 109 private import tango.text.locale.Data; 110 111 private import tango.time.Time; 112 113 private import tango.time.chrono.Hijri, 114 tango.time.chrono.Korean, 115 tango.time.chrono.Taiwan, 116 tango.time.chrono.Hebrew, 117 tango.time.chrono.Calendar, 118 tango.time.chrono.Japanese, 119 tango.time.chrono.Gregorian, 120 tango.time.chrono.ThaiBuddhist; 121 122 version (Windows) 123 private import tango.text.locale.Win32; 124 125 version (Posix) 126 private import tango.text.locale.Posix; 127 128 129 // Initializes an array. 130 private template arrayOf(T) { 131 private T[] arrayOf(T[] params ...) { 132 return params.dup; 133 } 134 } 135 136 137 /** 138 * Defines the types of cultures that can be retrieved from Culture.getCultures. 139 */ 140 public enum CultureTypes { 141 Neutral = 1, /// Refers to cultures that are associated with a language but not specific to a country or region. 142 Specific = 2, /// Refers to cultures that are specific to a country or region. 143 All = Neutral | Specific /// Refers to all cultures. 144 } 145 146 147 /** 148 * $(ANCHOR _IFormatService) 149 * Retrieves an object to control formatting. 150 * 151 * A class implements $(LINK2 #IFormatService_getFormat, getFormat) to retrieve an object that provides format information for the implementing type. 152 * Remarks: IFormatService is implemented by $(LINK2 #Culture, Culture), $(LINK2 #NumberFormat, NumberFormat) and $(LINK2 #DateTimeFormat, DateTimeFormat) to provide locale-specific formatting of 153 * numbers and date and time values. 154 */ 155 public interface IFormatService { 156 157 /** 158 * $(ANCHOR IFormatService_getFormat) 159 * Retrieves an object that supports formatting for the specified _type. 160 * Returns: The current instance if type is the same _type as the current instance; otherwise, null. 161 * Params: type = An object that specifies the _type of formatting to retrieve. 162 */ 163 Object getFormat(TypeInfo type); 164 165 } 166 167 /** 168 * $(ANCHOR _Culture) 169 * Provides information about a culture, such as its name, calendar and date and number format patterns. 170 * Remarks: tango.text.locale adopts the RFC 1766 standard for culture names in the format <language>"-"<region>. 171 * <language> is a lower-case two-letter code defined by ISO 639-1. <region> is an upper-case 172 * two-letter code defined by ISO 3166. For example, "en-GB" is UK English. 173 * $(BR)$(BR)There are three types of culture: invariant, neutral and specific. The invariant culture is not tied to 174 * any specific region, although it is associated with the English language. A neutral culture is associated with 175 * a language, but not with a region. A specific culture is associated with a language and a region. "es" is a neutral 176 * culture. "es-MX" is a specific culture. 177 * $(BR)$(BR)Instances of $(LINK2 #DateTimeFormat, DateTimeFormat) and $(LINK2 #NumberFormat, NumberFormat) cannot be created for neutral cultures. 178 * Examples: 179 * --- 180 * import tango.io.Stdout, tango.text.locale.Core; 181 * 182 * void main() { 183 * Culture culture = new Culture("it-IT"); 184 * 185 * Stdout.formatln("englishName: {}", culture.englishName); 186 * Stdout.formatln("nativeName: {}", culture.nativeName); 187 * Stdout.formatln("name: {}", culture.name); 188 * Stdout.formatln("parent: {}", culture.parent.name); 189 * Stdout.formatln("isNeutral: {}", culture.isNeutral); 190 * } 191 * 192 * // Produces the following output: 193 * // englishName: Italian (Italy) 194 * // nativeName: italiano (Italia) 195 * // name: it-IT 196 * // parent: it 197 * // isNeutral: false 198 * --- 199 */ 200 public class Culture : IFormatService { 201 202 private enum int LCID_INVARIANT = 0x007F; 203 204 private static Culture[immutable(char)[]] namedCultures; 205 private static Culture[int] idCultures; 206 private static Culture[immutable(char)[]] ietfCultures; 207 208 private static Culture currentCulture_; 209 private static Culture userDefaultCulture_; // The user's default culture (GetUserDefaultLCID). 210 private static Culture invariantCulture_; // The invariant culture is associated with the English language. 211 private Calendar calendar_; 212 private Culture parent_; 213 private const(CultureData)* cultureData_; 214 private bool isReadOnly_; 215 private NumberFormat numberFormat_; 216 private DateTimeFormat dateTimeFormat_; 217 218 shared static this() { 219 invariantCulture_ = new Culture(LCID_INVARIANT); 220 invariantCulture_.isReadOnly_ = true; 221 222 userDefaultCulture_ = new Culture(nativeMethods.getUserCulture()); 223 if (userDefaultCulture_ is null) 224 // Fallback 225 userDefaultCulture_ = invariantCulture; 226 else 227 userDefaultCulture_.isReadOnly_ = true; 228 } 229 230 static ~this() { 231 namedCultures = null; 232 idCultures = null; 233 ietfCultures = null; 234 } 235 236 /** 237 * Initializes a new Culture instance from the supplied name. 238 * Params: cultureName = The name of the Culture. 239 */ 240 public this(const(char)[] cultureName) { 241 cultureData_ = CultureData.getDataFromCultureName(cultureName); 242 } 243 244 /** 245 * Initializes a new Culture instance from the supplied culture identifier. 246 * Params: cultureID = The identifer (LCID) of the Culture. 247 * Remarks: Culture identifiers correspond to a Windows LCID. 248 */ 249 public this(int cultureID) { 250 cultureData_ = CultureData.getDataFromCultureID(cultureID); 251 } 252 253 /** 254 * Retrieves an object defining how to format the specified type. 255 * Params: type = The TypeInfo of the resulting formatting object. 256 * Returns: If type is typeid($(LINK2 #NumberFormat, NumberFormat)), the value of the $(LINK2 #Culture_numberFormat, numberFormat) property. If type is typeid($(LINK2 #DateTimeFormat, DateTimeFormat)), the 257 * value of the $(LINK2 #Culture_dateTimeFormat, dateTimeFormat) property. Otherwise, null. 258 * Remarks: Implements $(LINK2 #IFormatService_getFormat, IFormatService.getFormat). 259 */ 260 public Object getFormat(TypeInfo type) { 261 if (type is typeid(NumberFormat)) 262 return numberFormat; 263 else if (type is typeid(DateTimeFormat)) 264 return dateTimeFormat; 265 return null; 266 } 267 268 version (Clone) 269 { 270 /** 271 * Copies the current Culture instance. 272 * Returns: A copy of the current Culture instance. 273 * Remarks: The values of the $(LINK2 #Culture_numberFormat, numberFormat), $(LINK2 #Culture_dateTimeFormat, dateTimeFormat) and $(LINK2 #Culture_calendar, calendar) properties are copied also. 274 */ 275 public Object clone() { 276 Culture culture = cast(Culture)cloneObject(this); 277 if (!culture.isNeutral) { 278 if (dateTimeFormat_ !is null) 279 culture.dateTimeFormat_ = cast(DateTimeFormat)dateTimeFormat_.clone(); 280 if (numberFormat_ !is null) 281 culture.numberFormat_ = cast(NumberFormat)numberFormat_.clone(); 282 } 283 if (calendar_ !is null) 284 culture.calendar_ = cast(Calendar)calendar_.clone(); 285 return culture; 286 } 287 } 288 289 /** 290 * Returns a read-only instance of a culture using the specified culture identifier. 291 * Params: cultureID = The identifier of the culture. 292 * Returns: A read-only culture instance. 293 * Remarks: Instances returned by this method are cached. 294 */ 295 public static Culture getCulture(int cultureID) { 296 Culture culture = getCultureInternal(cultureID, null); 297 298 version (Posix) { 299 if (culture is null) 300 error ("Culture not found - if this was not tried set by the application, Tango\n" 301 ~ "will expect that a locale is set via environment variables LANG or LC_ALL."); 302 } 303 304 return culture; 305 } 306 307 /** 308 * Returns a read-only instance of a culture using the specified culture name. 309 * Params: cultureName = The name of the culture. 310 * Returns: A read-only culture instance. 311 * Remarks: Instances returned by this method are cached. 312 */ 313 public static Culture getCulture(const(char)[] cultureName) { 314 if (cultureName is null) 315 error("Value cannot be null."); 316 Culture culture = getCultureInternal(0, cultureName); 317 if (culture is null) 318 error("Culture name " ~ cultureName.idup ~ " is not supported."); 319 return culture; 320 } 321 322 /** 323 * Returns a read-only instance using the specified name, as defined by the RFC 3066 standard and maintained by the IETF. 324 * Params: name = The name of the language. 325 * Returns: A read-only culture instance. 326 */ 327 public static Culture getCultureFromIetfLanguageTag(const(char)[] name) { 328 if (name is null) 329 error("Value cannot be null."); 330 Culture culture = getCultureInternal(-1, name); 331 if (culture is null) 332 error("Culture IETF name " ~ name.idup ~ " is not a known IETF name."); 333 return culture; 334 } 335 336 private static Culture getCultureInternal(int cultureID, const(char)[] cname) { 337 // If cultureID is - 1, name is an IETF name; if it's 0, name is a culture name; otherwise, it's a valid LCID. 338 const(char)[] name = cname; 339 char[] temp_name; 340 foreach (i, c; cname) 341 if (c is '_') { 342 temp_name = cname.dup; 343 temp_name[i] = '-'; 344 name = temp_name; 345 break; 346 } 347 348 // Look up tables first. 349 if (cultureID == 0) { 350 if (Culture* culture = name in namedCultures) 351 return *culture; 352 } 353 else if (cultureID > 0) { 354 if (Culture* culture = cultureID in idCultures) 355 return *culture; 356 } 357 else if (cultureID == -1) { 358 if (Culture* culture = name in ietfCultures) 359 return *culture; 360 } 361 362 // Nothing found, create a new instance. 363 Culture culture; 364 365 try { 366 if (cultureID == -1) { 367 name = CultureData.getCultureNameFromIetfName(name); 368 if (name is null) 369 return null; 370 } 371 else if (cultureID == 0) 372 culture = new Culture(name); 373 else if (userDefaultCulture_ !is null && userDefaultCulture_.id == cultureID) { 374 culture = userDefaultCulture_; 375 } 376 else 377 culture = new Culture(cultureID); 378 } 379 catch (LocaleException) { 380 return null; 381 } 382 383 culture.isReadOnly_ = true; 384 385 // Now cache the new instance in all tables. 386 ietfCultures[culture.ietfLanguageTag] = culture; 387 namedCultures[culture.name] = culture; 388 idCultures[culture.id] = culture; 389 390 return culture; 391 } 392 393 /** 394 * Returns a list of cultures filtered by the specified $(LINK2 constants.html#CultureTypes, CultureTypes). 395 * Params: types = A combination of CultureTypes. 396 * Returns: An array of Culture instances containing cultures specified by types. 397 */ 398 public static Culture[] getCultures(CultureTypes types) { 399 bool includeSpecific = (types & CultureTypes.Specific) != 0; 400 bool includeNeutral = (types & CultureTypes.Neutral) != 0; 401 402 int[] cultures; 403 for (int i = 0; i < CultureData.cultureDataTable.length; i++) { 404 if ((CultureData.cultureDataTable[i].isNeutral && includeNeutral) || (!CultureData.cultureDataTable[i].isNeutral && includeSpecific)) 405 cultures ~= CultureData.cultureDataTable[i].lcid; 406 } 407 408 Culture[] result = new Culture[cultures.length]; 409 foreach (int i, int cultureID; cultures) 410 result[i] = new Culture(cultureID); 411 return result; 412 } 413 414 /** 415 * Returns the name of the Culture. 416 * Returns: A string containing the name of the Culture in the format <language>"-"<region>. 417 */ 418 public override immutable(char)[] toString() { 419 return cultureData_.name.idup; 420 } 421 422 public override bool opEquals(Object obj) { 423 if (obj is this) 424 return true; 425 Culture other = cast(Culture)obj; 426 if (other is null) 427 return false; 428 return other.name == name; // This needs to be changed so it's culturally aware. 429 } 430 431 /** 432 * $(ANCHOR Culture_current) 433 * $(I Property.) Retrieves the culture of the current user. 434 * Returns: The Culture instance representing the user's current culture. 435 */ 436 @property public static Culture current() { 437 if (currentCulture_ !is null) 438 return currentCulture_; 439 440 if (userDefaultCulture_ !is null) { 441 // If the user has changed their locale settings since last we checked, invalidate our data. 442 if (userDefaultCulture_.id != nativeMethods.getUserCulture()) 443 userDefaultCulture_ = null; 444 } 445 if (userDefaultCulture_ is null) { 446 userDefaultCulture_ = new Culture(nativeMethods.getUserCulture()); 447 if (userDefaultCulture_ is null) 448 userDefaultCulture_ = invariantCulture; 449 else 450 userDefaultCulture_.isReadOnly_ = true; 451 } 452 453 return userDefaultCulture_; 454 } 455 /** 456 * $(I Property.) Assigns the culture of the _current user. 457 * Params: value = The Culture instance representing the user's _current culture. 458 * Examples: 459 * The following examples shows how to change the _current culture. 460 * --- 461 * import tango.io.Print, tango.text.locale.Common; 462 * 463 * void main() { 464 * // Displays the name of the current culture. 465 * Println("The current culture is %s.", Culture.current.englishName); 466 * 467 * // Changes the current culture to el-GR. 468 * Culture.current = new Culture("el-GR"); 469 * Println("The current culture is now %s.", Culture.current.englishName); 470 * } 471 * 472 * // Produces the following output: 473 * // The current culture is English (United Kingdom). 474 * // The current culture is now Greek (Greece). 475 * --- 476 */ 477 @property public static void current(Culture value) { 478 checkNeutral(value); 479 nativeMethods.setUserCulture(value.id); 480 currentCulture_ = value; 481 } 482 483 /** 484 * $(I Property.) Retrieves the invariant Culture. 485 * Returns: The Culture instance that is invariant. 486 * Remarks: The invariant culture is culture-independent. It is not tied to any specific region, but is associated 487 * with the English language. 488 */ 489 @property public static Culture invariantCulture() { 490 return invariantCulture_; 491 } 492 493 /** 494 * $(I Property.) Retrieves the identifier of the Culture. 495 * Returns: The culture identifier of the current instance. 496 * Remarks: The culture identifier corresponds to the Windows locale identifier (LCID). It can therefore be used when 497 * interfacing with the Windows NLS functions. 498 */ 499 @property public const int id() { 500 return cultureData_.lcid; 501 } 502 503 /** 504 * $(ANCHOR Culture_name) 505 * $(I Property.) Retrieves the name of the Culture in the format <language>"-"<region>. 506 * Returns: The name of the current instance. For example, the name of the UK English culture is "en-GB". 507 */ 508 @property public const const(char)[] name() { 509 return cultureData_.name; 510 } 511 512 /** 513 * $(I Property.) Retrieves the name of the Culture in the format <languagename> (<regionname>) in English. 514 * Returns: The name of the current instance in English. For example, the englishName of the UK English culture 515 * is "English (United Kingdom)". 516 */ 517 @property public const const(char)[] englishName() { 518 return cultureData_.englishName; 519 } 520 521 /** 522 * $(I Property.) Retrieves the name of the Culture in the format <languagename> (<regionname>) in its native language. 523 * Returns: The name of the current instance in its native language. For example, if Culture.name is "de-DE", nativeName is 524 * "Deutsch (Deutschland)". 525 */ 526 @property public const const(char)[] nativeName() { 527 return cultureData_.nativeName; 528 } 529 530 /** 531 * $(I Property.) Retrieves the two-letter language code of the culture. 532 * Returns: The two-letter language code of the Culture instance. For example, the twoLetterLanguageName for English is "en". 533 */ 534 @property public const const(char)[] twoLetterLanguageName() { 535 return cultureData_.isoLangName; 536 } 537 538 /** 539 * $(I Property.) Retrieves the three-letter language code of the culture. 540 * Returns: The three-letter language code of the Culture instance. For example, the threeLetterLanguageName for English is "eng". 541 */ 542 @property public const const(char)[] threeLetterLanguageName() { 543 return cultureData_.isoLangName2; 544 } 545 546 /** 547 * $(I Property.) Retrieves the RFC 3066 identification for a language. 548 * Returns: A string representing the RFC 3066 language identification. 549 */ 550 @property public const final const(char)[] ietfLanguageTag() { 551 return cultureData_.ietfTag; 552 } 553 554 /** 555 * $(I Property.) Retrieves the Culture representing the parent of the current instance. 556 * Returns: The Culture representing the parent of the current instance. 557 */ 558 @property public Culture parent() { 559 if (parent_ is null) { 560 try { 561 int parentCulture = cultureData_.parent; 562 if (parentCulture == LCID_INVARIANT) 563 parent_ = invariantCulture; 564 else 565 parent_ = new Culture(parentCulture); 566 } 567 catch { 568 parent_ = invariantCulture; 569 } 570 } 571 return parent_; 572 } 573 574 /** 575 * $(I Property.) Retrieves a value indicating whether the current instance is a neutral culture. 576 * Returns: true is the current Culture represents a neutral culture; otherwise, false. 577 * Examples: 578 * The following example displays which cultures using Chinese are neutral. 579 * --- 580 * import tango.io.Print, tango.text.locale.Common; 581 * 582 * void main() { 583 * foreach (c; Culture.getCultures(CultureTypes.All)) { 584 * if (c.twoLetterLanguageName == "zh") { 585 * Print(c.englishName); 586 * if (c.isNeutral) 587 * Println("neutral"); 588 * else 589 * Println("specific"); 590 * } 591 * } 592 * } 593 * 594 * // Produces the following output: 595 * // Chinese (Simplified) - neutral 596 * // Chinese (Taiwan) - specific 597 * // Chinese (People's Republic of China) - specific 598 * // Chinese (Hong Kong S.A.R.) - specific 599 * // Chinese (Singapore) - specific 600 * // Chinese (Macao S.A.R.) - specific 601 * // Chinese (Traditional) - neutral 602 * --- 603 */ 604 @property public const bool isNeutral() { 605 return cultureData_.isNeutral; 606 } 607 608 /** 609 * $(I Property.) Retrieves a value indicating whether the instance is read-only. 610 * Returns: true if the instance is read-only; otherwise, false. 611 * Remarks: If the culture is read-only, the $(LINK2 #Culture_dateTimeFormat, dateTimeFormat) and $(LINK2 #Culture_numberFormat, numberFormat) properties return 612 * read-only instances. 613 */ 614 @property public const final bool isReadOnly() { 615 return isReadOnly_; 616 } 617 618 /** 619 * $(ANCHOR Culture_calendar) 620 * $(I Property.) Retrieves the calendar used by the culture. 621 * Returns: A Calendar instance respresenting the calendar used by the culture. 622 */ 623 @property public Calendar calendar() { 624 if (calendar_ is null) { 625 calendar_ = getCalendarInstance(cultureData_.calendarType, isReadOnly_); 626 } 627 return calendar_; 628 } 629 630 /** 631 * $(I Property.) Retrieves the list of calendars that can be used by the culture. 632 * Returns: An array of type Calendar representing the calendars that can be used by the culture. 633 */ 634 @property public Calendar[] optionalCalendars() { 635 Calendar[] cals = new Calendar[cultureData_.optionalCalendars.length]; 636 foreach (int i, int calID; cultureData_.optionalCalendars) 637 cals[i] = getCalendarInstance(calID); 638 return cals; 639 } 640 641 /** 642 * $(ANCHOR Culture_numberFormat) 643 * $(I Property.) Retrieves a NumberFormat defining the culturally appropriate format for displaying numbers and currency. 644 * Returns: A NumberFormat defining the culturally appropriate format for displaying numbers and currency. 645 */ 646 @property public NumberFormat numberFormat() { 647 checkNeutral(this); 648 if (numberFormat_ is null) { 649 numberFormat_ = new NumberFormat(cultureData_); 650 numberFormat_.isReadOnly_ = isReadOnly_; 651 } 652 return numberFormat_; 653 } 654 /** 655 * $(I Property.) Assigns a NumberFormat defining the culturally appropriate format for displaying numbers and currency. 656 * Params: values = A NumberFormat defining the culturally appropriate format for displaying numbers and currency. 657 */ 658 @property public void numberFormat(NumberFormat value) { 659 checkReadOnly(); 660 numberFormat_ = value; 661 } 662 663 /** 664 * $(ANCHOR Culture_dateTimeFormat) 665 * $(I Property.) Retrieves a DateTimeFormat defining the culturally appropriate format for displaying dates and times. 666 * Returns: A DateTimeFormat defining the culturally appropriate format for displaying dates and times. 667 */ 668 @property public DateTimeFormat dateTimeFormat() { 669 checkNeutral(this); 670 if (dateTimeFormat_ is null) { 671 dateTimeFormat_ = new DateTimeFormat(cultureData_, calendar); 672 dateTimeFormat_.isReadOnly_ = isReadOnly_; 673 } 674 return dateTimeFormat_; 675 } 676 /** 677 * $(I Property.) Assigns a DateTimeFormat defining the culturally appropriate format for displaying dates and times. 678 * Params: values = A DateTimeFormat defining the culturally appropriate format for displaying dates and times. 679 */ 680 @property public void dateTimeFormat(DateTimeFormat value) { 681 checkReadOnly(); 682 dateTimeFormat_ = value; 683 } 684 685 private static void checkNeutral(Culture culture) { 686 if (culture.isNeutral) 687 error("Culture '" ~ culture.name.idup ~ "' is a neutral culture. It cannot be used in formatting and therefore cannot be set as the current culture."); 688 } 689 690 private void checkReadOnly() { 691 if (isReadOnly_) 692 error("Instance is read-only."); 693 } 694 695 private static Calendar getCalendarInstance(int calendarType, bool readOnly=false) { 696 switch (calendarType) { 697 case Calendar.JAPAN: 698 return new Japanese(); 699 case Calendar.TAIWAN: 700 return new Taiwan(); 701 case Calendar.KOREA: 702 return new Korean(); 703 case Calendar.HIJRI: 704 return new Hijri(); 705 case Calendar.THAI: 706 return new ThaiBuddhist(); 707 case Calendar.HEBREW: 708 return new Hebrew; 709 case Calendar.GREGORIAN_US: 710 case Calendar.GREGORIAN_ME_FRENCH: 711 case Calendar.GREGORIAN_ARABIC: 712 case Calendar.GREGORIAN_XLIT_ENGLISH: 713 case Calendar.GREGORIAN_XLIT_FRENCH: 714 return new Gregorian(cast(Gregorian.Type) calendarType); 715 default: 716 break; 717 } 718 return new Gregorian(); 719 } 720 721 } 722 723 /** 724 * $(ANCHOR _Region) 725 * Provides information about a region. 726 * Remarks: Region does not represent user preferences. It does not depend on the user's language or culture. 727 * Examples: 728 * The following example displays some of the properties of the Region class: 729 * --- 730 * import tango.io.Print, tango.text.locale.Common; 731 * 732 * void main() { 733 * Region region = new Region("en-GB"); 734 * Println("name: %s", region.name); 735 * Println("englishName: %s", region.englishName); 736 * Println("isMetric: %s", region.isMetric); 737 * Println("currencySymbol: %s", region.currencySymbol); 738 * Println("isoCurrencySymbol: %s", region.isoCurrencySymbol); 739 * } 740 * 741 * // Produces the following output. 742 * // name: en-GB 743 * // englishName: United Kingdom 744 * // isMetric: true 745 * // currencySymbol: £ 746 * // isoCurrencySymbol: GBP 747 * --- 748 */ 749 public class Region { 750 751 private const(CultureData)* cultureData_; 752 private static Region currentRegion_; 753 private const(char)[] name_; 754 755 /** 756 * Initializes a new Region instance based on the region associated with the specified culture identifier. 757 * Params: cultureID = A culture indentifier. 758 * Remarks: The name of the Region instance is set to the ISO 3166 two-letter code for that region. 759 */ 760 public this(int cultureID) { 761 cultureData_ = CultureData.getDataFromCultureID(cultureID); 762 if (cultureData_.isNeutral) 763 error ("Cannot use a neutral culture to create a region."); 764 name_ = cultureData_.regionName; 765 } 766 767 /** 768 * $(ANCHOR Region_ctor_name) 769 * Initializes a new Region instance based on the region specified by name. 770 * Params: name = A two-letter ISO 3166 code for the region. Or, a culture $(LINK2 #Culture_name, _name) consisting of the language and region. 771 */ 772 public this(const(char)[] name) { 773 cultureData_ = CultureData.getDataFromRegionName(name); 774 name_ = name; 775 if (cultureData_.isNeutral) 776 error ("The region name " ~ name.idup ~ " corresponds to a neutral culture and cannot be used to create a region."); 777 } 778 779 package this(const(CultureData)* cultureData) { 780 cultureData_ = cultureData; 781 name_ = cultureData.regionName; 782 } 783 784 /** 785 * $(I Property.) Retrieves the Region used by the current $(LINK2 #Culture, Culture). 786 * Returns: The Region instance associated with the current Culture. 787 */ 788 @property public static Region current() { 789 if (currentRegion_ is null) 790 currentRegion_ = new Region(Culture.current.cultureData_); 791 return currentRegion_; 792 } 793 794 /** 795 * $(I Property.) Retrieves a unique identifier for the geographical location of the region. 796 * Returns: An $(B int) uniquely identifying the geographical location. 797 */ 798 @property public const int geoID() { 799 return cultureData_.geoId; 800 } 801 802 /** 803 * $(ANCHOR Region_name) 804 * $(I Property.) Retrieves the ISO 3166 code, or the name, of the current Region. 805 * Returns: The value specified by the name parameter of the $(LINK2 #Region_ctor_name, Region(char[])) constructor. 806 */ 807 @property public const const(char)[] name() { 808 return name_; 809 } 810 811 /** 812 * $(I Property.) Retrieves the full name of the region in English. 813 * Returns: The full name of the region in English. 814 */ 815 @property public const const(char)[] englishName() { 816 return cultureData_.englishCountry; 817 } 818 819 /** 820 * $(I Property.) Retrieves the full name of the region in its native language. 821 * Returns: The full name of the region in the language associated with the region code. 822 */ 823 @property public const const(char)[] nativeName() { 824 return cultureData_.nativeCountry; 825 } 826 827 /** 828 * $(I Property.) Retrieves the two-letter ISO 3166 code of the region. 829 * Returns: The two-letter ISO 3166 code of the region. 830 */ 831 @property public const const(char)[] twoLetterRegionName() { 832 return cultureData_.regionName; 833 } 834 835 /** 836 * $(I Property.) Retrieves the three-letter ISO 3166 code of the region. 837 * Returns: The three-letter ISO 3166 code of the region. 838 */ 839 @property public const const(char)[] threeLetterRegionName() { 840 return cultureData_.isoRegionName; 841 } 842 843 /** 844 * $(I Property.) Retrieves the currency symbol of the region. 845 * Returns: The currency symbol of the region. 846 */ 847 @property public const const(char)[] currencySymbol() { 848 return cultureData_.currency; 849 } 850 851 /** 852 * $(I Property.) Retrieves the three-character currency symbol of the region. 853 * Returns: The three-character currency symbol of the region. 854 */ 855 @property public const const(char)[] isoCurrencySymbol() { 856 return cultureData_.intlSymbol; 857 } 858 859 /** 860 * $(I Property.) Retrieves the name in English of the currency used in the region. 861 * Returns: The name in English of the currency used in the region. 862 */ 863 @property public const const(char)[] currencyEnglishName() { 864 return cultureData_.englishCurrency; 865 } 866 867 /** 868 * $(I Property.) Retrieves the name in the native language of the region of the currency used in the region. 869 * Returns: The name in the native language of the region of the currency used in the region. 870 */ 871 @property public const const(char)[] currencyNativeName() { 872 return cultureData_.nativeCurrency; 873 } 874 875 /** 876 * $(I Property.) Retrieves a value indicating whether the region uses the metric system for measurements. 877 * Returns: true is the region uses the metric system; otherwise, false. 878 */ 879 @property public const bool isMetric() { 880 return cultureData_.isMetric; 881 } 882 883 /** 884 * Returns a string containing the ISO 3166 code, or the $(LINK2 #Region_name, name), of the current Region. 885 * Returns: A string containing the ISO 3166 code, or the name, of the current Region. 886 */ 887 public override immutable(char)[] toString() { 888 return name_.idup; 889 } 890 891 } 892 893 /** 894 * $(ANCHOR _NumberFormat) 895 * Determines how numbers are formatted, according to the current culture. 896 * Remarks: Numbers are formatted using format patterns retrieved from a NumberFormat instance. 897 * This class implements $(LINK2 #IFormatService_getFormat, IFormatService.getFormat). 898 * Examples: 899 * The following example shows how to retrieve an instance of NumberFormat for a Culture 900 * and use it to display number formatting information. 901 * --- 902 * import tango.io.Print, tango.text.locale.Common; 903 * 904 * void main(char[][] args) { 905 * foreach (c; Culture.getCultures(CultureTypes.Specific)) { 906 * if (c.twoLetterLanguageName == "en") { 907 * NumberFormat fmt = c.numberFormat; 908 * Println("The currency symbol for %s is '%s'", 909 * c.englishName, 910 * fmt.currencySymbol); 911 * } 912 * } 913 * } 914 * 915 * // Produces the following output: 916 * // The currency symbol for English (United States) is '$' 917 * // The currency symbol for English (United Kingdom) is '£' 918 * // The currency symbol for English (Australia) is '$' 919 * // The currency symbol for English (Canada) is '$' 920 * // The currency symbol for English (New Zealand) is '$' 921 * // The currency symbol for English (Ireland) is '€' 922 * // The currency symbol for English (South Africa) is 'R' 923 * // The currency symbol for English (Jamaica) is 'J$' 924 * // The currency symbol for English (Caribbean) is '$' 925 * // The currency symbol for English (Belize) is 'BZ$' 926 * // The currency symbol for English (Trinidad and Tobago) is 'TT$' 927 * // The currency symbol for English (Zimbabwe) is 'Z$' 928 * // The currency symbol for English (Republic of the Philippines) is 'Php' 929 *--- 930 */ 931 public class NumberFormat : IFormatService { 932 933 package bool isReadOnly_; 934 private static NumberFormat invariantFormat_; 935 936 private int numberDecimalDigits_; 937 private int numberNegativePattern_; 938 private int currencyDecimalDigits_; 939 private int currencyNegativePattern_; 940 private int currencyPositivePattern_; 941 private const(int)[] numberGroupSizes_; 942 private const(int)[] currencyGroupSizes_; 943 private const(char)[] numberGroupSeparator_; 944 private const(char)[] numberDecimalSeparator_; 945 private const(char)[] currencyGroupSeparator_; 946 private const(char)[] currencyDecimalSeparator_; 947 private const(char)[] currencySymbol_; 948 private const(char)[] negativeSign_; 949 private const(char)[] positiveSign_; 950 private const(char)[] nanSymbol_; 951 private const(char)[] negativeInfinitySymbol_; 952 private const(char)[] positiveInfinitySymbol_; 953 private const(char[])[] nativeDigits_; 954 955 /** 956 * Initializes a new, culturally independent instance. 957 * 958 * Remarks: Modify the properties of the new instance to define custom formatting. 959 */ 960 public this() { 961 this(null); 962 } 963 964 package this(const(CultureData)* cultureData) { 965 // Initialize invariant data. 966 numberDecimalDigits_ = 2; 967 numberNegativePattern_ = 1; 968 currencyDecimalDigits_ = 2; 969 numberGroupSizes_ = arrayOf!(int)(3); 970 currencyGroupSizes_ = arrayOf!(int)(3); 971 numberGroupSeparator_ = ","; 972 numberDecimalSeparator_ = "."; 973 currencyGroupSeparator_ = ","; 974 currencyDecimalSeparator_ = "."; 975 currencySymbol_ = "\u00A4"; 976 negativeSign_ = "-"; 977 positiveSign_ = "+"; 978 nanSymbol_ = "NaN"; 979 negativeInfinitySymbol_ = "-Infinity"; 980 positiveInfinitySymbol_ = "Infinity"; 981 nativeDigits_ = arrayOf!(const(char)[])("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); 982 983 if (cultureData !is null && cultureData.lcid != Culture.LCID_INVARIANT) { 984 // Initialize culture-specific data. 985 numberDecimalDigits_ = cultureData.digits; 986 numberNegativePattern_ = cultureData.negativeNumber; 987 currencyDecimalDigits_ = cultureData.currencyDigits; 988 currencyNegativePattern_ = cultureData.negativeCurrency; 989 currencyPositivePattern_ = cultureData.positiveCurrency; 990 numberGroupSizes_ = cultureData.grouping; 991 currencyGroupSizes_ = cultureData.monetaryGrouping; 992 numberGroupSeparator_ = cultureData.thousand; 993 numberDecimalSeparator_ = cultureData.decimal; 994 currencyGroupSeparator_ = cultureData.monetaryThousand; 995 currencyDecimalSeparator_ = cultureData.monetaryDecimal; 996 currencySymbol_ = cultureData.currency; 997 negativeSign_ = cultureData.negativeSign; 998 positiveSign_ = cultureData.positiveSign; 999 nanSymbol_ = cultureData.nan; 1000 negativeInfinitySymbol_ = cultureData.negInfinity; 1001 positiveInfinitySymbol_ = cultureData.posInfinity; 1002 nativeDigits_ = cultureData.nativeDigits; 1003 } 1004 } 1005 1006 /** 1007 * Retrieves an object defining how to format the specified type. 1008 * Params: type = The TypeInfo of the resulting formatting object. 1009 * Returns: If type is typeid($(LINK2 #NumberFormat, NumberFormat)), the current NumberFormat instance. Otherwise, null. 1010 * Remarks: Implements $(LINK2 #IFormatService_getFormat, IFormatService.getFormat). 1011 */ 1012 public Object getFormat(TypeInfo type) { 1013 return (type is typeid(NumberFormat)) ? this : null; 1014 } 1015 1016 version (Clone) 1017 { 1018 /** 1019 * Creates a copy of the instance. 1020 */ 1021 public Object clone() { 1022 NumberFormat copy = cast(NumberFormat)cloneObject(this); 1023 copy.isReadOnly_ = false; 1024 return copy; 1025 } 1026 } 1027 1028 /** 1029 * Retrieves the NumberFormat for the specified $(LINK2 #IFormatService, IFormatService). 1030 * Params: formatService = The IFormatService used to retrieve NumberFormat. 1031 * Returns: The NumberFormat for the specified IFormatService. 1032 * Remarks: The method calls $(LINK2 #IFormatService_getFormat, IFormatService.getFormat) with typeof(NumberFormat). If formatService is null, 1033 * then the value of the current property is returned. 1034 */ 1035 public static NumberFormat getInstance(IFormatService formatService) { 1036 Culture culture = cast(Culture)formatService; 1037 if (culture !is null) { 1038 if (culture.numberFormat_ !is null) 1039 return culture.numberFormat_; 1040 return culture.numberFormat; 1041 } 1042 if (NumberFormat numberFormat = cast(NumberFormat)formatService) 1043 return numberFormat; 1044 if (formatService !is null) { 1045 if (NumberFormat numberFormat = cast(NumberFormat)(formatService.getFormat(typeid(NumberFormat)))) 1046 return numberFormat; 1047 } 1048 return current; 1049 } 1050 1051 /** 1052 * $(I Property.) Retrieves a read-only NumberFormat instance from the current culture. 1053 * Returns: A read-only NumberFormat instance from the current culture. 1054 */ 1055 @property public static NumberFormat current() { 1056 return Culture.current.numberFormat; 1057 } 1058 1059 /** 1060 * $(ANCHOR NumberFormat_invariantFormat) 1061 * $(I Property.) Retrieves the read-only, culturally independent NumberFormat instance. 1062 * Returns: The read-only, culturally independent NumberFormat instance. 1063 */ 1064 public static NumberFormat invariantFormat() { 1065 if (invariantFormat_ is null) { 1066 invariantFormat_ = new NumberFormat; 1067 invariantFormat_.isReadOnly_ = true; 1068 } 1069 return invariantFormat_; 1070 } 1071 1072 /** 1073 * $(I Property.) Retrieves a value indicating whether the instance is read-only. 1074 * Returns: true if the instance is read-only; otherwise, false. 1075 */ 1076 @property public final const bool isReadOnly() { 1077 return isReadOnly_; 1078 } 1079 1080 /** 1081 * $(I Property.) Retrieves the number of decimal places used for numbers. 1082 * Returns: The number of decimal places used for numbers. For $(LINK2 #NumberFormat_invariantFormat, invariantFormat), the default is 2. 1083 */ 1084 @property public final const int numberDecimalDigits() { 1085 return numberDecimalDigits_; 1086 } 1087 /** 1088 * Assigns the number of decimal digits used for numbers. 1089 * Params: value = The number of decimal places used for numbers. 1090 * Throws: Exception if the property is being set and the instance is read-only. 1091 * Examples: 1092 * The following example shows the effect of changing numberDecimalDigits. 1093 * --- 1094 * import tango.io.Print, tango.text.locale.Common; 1095 * 1096 * void main() { 1097 * // Get the NumberFormat from the en-GB culture. 1098 * NumberFormat fmt = (new Culture("en-GB")).numberFormat; 1099 * 1100 * // Display a value with the default number of decimal digits. 1101 * int n = 5678; 1102 * Println(Formatter.format(fmt, "{0:N}", n)); 1103 * 1104 * // Display the value with six decimal digits. 1105 * fmt.numberDecimalDigits = 6; 1106 * Println(Formatter.format(fmt, "{0:N}", n)); 1107 * } 1108 * 1109 * // Produces the following output: 1110 * // 5,678.00 1111 * // 5,678.000000 1112 * --- 1113 */ 1114 @property public final void numberDecimalDigits(int value) { 1115 checkReadOnly(); 1116 numberDecimalDigits_ = value; 1117 } 1118 1119 /** 1120 * $(I Property.) Retrieves the format pattern for negative numbers. 1121 * Returns: The format pattern for negative numbers. For invariantFormat, the default is 1 (representing "-n"). 1122 * Remarks: The following table shows valid values for this property. 1123 * 1124 * <table class="definitionTable"> 1125 * <tr><th>Value</th><th>Pattern</th></tr> 1126 * <tr><td>0</td><td>(n)</td></tr> 1127 * <tr><td>1</td><td>-n</td></tr> 1128 * <tr><td>2</td><td>- n</td></tr> 1129 * <tr><td>3</td><td>n-</td></tr> 1130 * <tr><td>4</td><td>n -</td></tr> 1131 * </table> 1132 */ 1133 @property public final const int numberNegativePattern() { 1134 return numberNegativePattern_; 1135 } 1136 /** 1137 * $(I Property.) Assigns the format pattern for negative numbers. 1138 * Params: value = The format pattern for negative numbers. 1139 * Examples: 1140 * The following example shows the effect of the different patterns. 1141 * --- 1142 * import tango.io.Print, tango.text.locale.Common; 1143 * 1144 * void main() { 1145 * NumberFormat fmt = new NumberFormat; 1146 * int n = -5678; 1147 * 1148 * // Display the default pattern. 1149 * Println(Formatter.format(fmt, "{0:N}", n)); 1150 * 1151 * // Display all patterns. 1152 * for (int i = 0; i <= 4; i++) { 1153 * fmt.numberNegativePattern = i; 1154 * Println(Formatter.format(fmt, "{0:N}", n)); 1155 * } 1156 * } 1157 * 1158 * // Produces the following output: 1159 * // (5,678.00) 1160 * // (5,678.00) 1161 * // -5,678.00 1162 * // - 5,678.00 1163 * // 5,678.00- 1164 * // 5,678.00 - 1165 * --- 1166 */ 1167 @property public final void numberNegativePattern(int value) { 1168 checkReadOnly(); 1169 numberNegativePattern_ = value; 1170 } 1171 1172 /** 1173 * $(I Property.) Retrieves the number of decimal places to use in currency values. 1174 * Returns: The number of decimal digits to use in currency values. 1175 */ 1176 @property public const final int currencyDecimalDigits() { 1177 return currencyDecimalDigits_; 1178 } 1179 /** 1180 * $(I Property.) Assigns the number of decimal places to use in currency values. 1181 * Params: value = The number of decimal digits to use in currency values. 1182 */ 1183 @property public final void currencyDecimalDigits(int value) { 1184 checkReadOnly(); 1185 currencyDecimalDigits_ = value; 1186 } 1187 1188 /** 1189 * $(I Property.) Retrieves the formal pattern to use for negative currency values. 1190 * Returns: The format pattern to use for negative currency values. 1191 */ 1192 @property public const final int currencyNegativePattern() { 1193 return currencyNegativePattern_; 1194 } 1195 /** 1196 * $(I Property.) Assigns the formal pattern to use for negative currency values. 1197 * Params: value = The format pattern to use for negative currency values. 1198 */ 1199 @property public final void currencyNegativePattern(int value) { 1200 checkReadOnly(); 1201 currencyNegativePattern_ = value; 1202 } 1203 1204 /** 1205 * $(I Property.) Retrieves the formal pattern to use for positive currency values. 1206 * Returns: The format pattern to use for positive currency values. 1207 */ 1208 @property public const final int currencyPositivePattern() { 1209 return currencyPositivePattern_; 1210 } 1211 /** 1212 * $(I Property.) Assigns the formal pattern to use for positive currency values. 1213 * Returns: The format pattern to use for positive currency values. 1214 */ 1215 @property public final void currencyPositivePattern(int value) { 1216 checkReadOnly(); 1217 currencyPositivePattern_ = value; 1218 } 1219 1220 /** 1221 * $(I Property.) Retrieves the number of digits int each group to the left of the decimal place in numbers. 1222 * Returns: The number of digits int each group to the left of the decimal place in numbers. 1223 */ 1224 @property public const final const(int)[] numberGroupSizes() { 1225 return numberGroupSizes_; 1226 } 1227 /** 1228 * $(I Property.) Assigns the number of digits int each group to the left of the decimal place in numbers. 1229 * Params: value = The number of digits int each group to the left of the decimal place in numbers. 1230 */ 1231 @property public final void numberGroupSizes(const(int)[] value) { 1232 checkReadOnly(); 1233 numberGroupSizes_ = value; 1234 } 1235 1236 /** 1237 * $(I Property.) Retrieves the number of digits int each group to the left of the decimal place in currency values. 1238 * Returns: The number of digits int each group to the left of the decimal place in currency values. 1239 */ 1240 @property public const final const(int)[] currencyGroupSizes() { 1241 return currencyGroupSizes_; 1242 } 1243 /** 1244 * $(I Property.) Assigns the number of digits int each group to the left of the decimal place in currency values. 1245 * Params: value = The number of digits int each group to the left of the decimal place in currency values. 1246 */ 1247 @property public final void currencyGroupSizes(const(int)[] value) { 1248 checkReadOnly(); 1249 currencyGroupSizes_ = value; 1250 } 1251 1252 /** 1253 * $(I Property.) Retrieves the string separating groups of digits to the left of the decimal place in numbers. 1254 * Returns: The string separating groups of digits to the left of the decimal place in numbers. For example, ",". 1255 */ 1256 @property public const final const(char)[] numberGroupSeparator() { 1257 return numberGroupSeparator_; 1258 } 1259 /** 1260 * $(I Property.) Assigns the string separating groups of digits to the left of the decimal place in numbers. 1261 * Params: value = The string separating groups of digits to the left of the decimal place in numbers. 1262 */ 1263 @property public final void numberGroupSeparator(const(char)[] value) { 1264 checkReadOnly(); 1265 numberGroupSeparator_ = value; 1266 } 1267 1268 /** 1269 * $(I Property.) Retrieves the string used as the decimal separator in numbers. 1270 * Returns: The string used as the decimal separator in numbers. For example, ".". 1271 */ 1272 @property public const final const(char)[] numberDecimalSeparator() { 1273 return numberDecimalSeparator_; 1274 } 1275 /** 1276 * $(I Property.) Assigns the string used as the decimal separator in numbers. 1277 * Params: value = The string used as the decimal separator in numbers. 1278 */ 1279 @property public final void numberDecimalSeparator(const(char)[] value) { 1280 checkReadOnly(); 1281 numberDecimalSeparator_ = value; 1282 } 1283 1284 /** 1285 * $(I Property.) Retrieves the string separating groups of digits to the left of the decimal place in currency values. 1286 * Returns: The string separating groups of digits to the left of the decimal place in currency values. For example, ",". 1287 */ 1288 @property public const final const(char)[] currencyGroupSeparator() { 1289 return currencyGroupSeparator_; 1290 } 1291 /** 1292 * $(I Property.) Assigns the string separating groups of digits to the left of the decimal place in currency values. 1293 * Params: value = The string separating groups of digits to the left of the decimal place in currency values. 1294 */ 1295 @property public final void currencyGroupSeparator(const(char)[] value) { 1296 checkReadOnly(); 1297 currencyGroupSeparator_ = value; 1298 } 1299 1300 /** 1301 * $(I Property.) Retrieves the string used as the decimal separator in currency values. 1302 * Returns: The string used as the decimal separator in currency values. For example, ".". 1303 */ 1304 @property public const final const(char)[] currencyDecimalSeparator() { 1305 return currencyDecimalSeparator_; 1306 } 1307 /** 1308 * $(I Property.) Assigns the string used as the decimal separator in currency values. 1309 * Params: value = The string used as the decimal separator in currency values. 1310 */ 1311 @property public final void currencyDecimalSeparator(const(char)[] value) { 1312 checkReadOnly(); 1313 currencyDecimalSeparator_ = value; 1314 } 1315 1316 /** 1317 * $(I Property.) Retrieves the string used as the currency symbol. 1318 * Returns: The string used as the currency symbol. For example, "£". 1319 */ 1320 @property public const final const(char)[] currencySymbol() { 1321 return currencySymbol_; 1322 } 1323 /** 1324 * $(I Property.) Assigns the string used as the currency symbol. 1325 * Params: value = The string used as the currency symbol. 1326 */ 1327 @property public final void currencySymbol(const(char)[] value) { 1328 checkReadOnly(); 1329 currencySymbol_ = value; 1330 } 1331 1332 /** 1333 * $(I Property.) Retrieves the string denoting that a number is negative. 1334 * Returns: The string denoting that a number is negative. For example, "-". 1335 */ 1336 @property public const final const(char)[] negativeSign() { 1337 return negativeSign_; 1338 } 1339 /** 1340 * $(I Property.) Assigns the string denoting that a number is negative. 1341 * Params: value = The string denoting that a number is negative. 1342 */ 1343 @property public final void negativeSign(const(char)[] value) { 1344 checkReadOnly(); 1345 negativeSign_ = value; 1346 } 1347 1348 /** 1349 * $(I Property.) Retrieves the string denoting that a number is positive. 1350 * Returns: The string denoting that a number is positive. For example, "+". 1351 */ 1352 @property public const final const(char)[] positiveSign() { 1353 return positiveSign_; 1354 } 1355 /** 1356 * $(I Property.) Assigns the string denoting that a number is positive. 1357 * Params: value = The string denoting that a number is positive. 1358 */ 1359 @property public final void positiveSign(const(char)[] value) { 1360 checkReadOnly(); 1361 positiveSign_ = value; 1362 } 1363 1364 /** 1365 * $(I Property.) Retrieves the string representing the NaN (not a number) value. 1366 * Returns: The string representing the NaN value. For example, "NaN". 1367 */ 1368 @property public const final const(char)[] nanSymbol() { 1369 return nanSymbol_; 1370 } 1371 /** 1372 * $(I Property.) Assigns the string representing the NaN (not a number) value. 1373 * Params: value = The string representing the NaN value. 1374 */ 1375 @property public final void nanSymbol(const(char)[] value) { 1376 checkReadOnly(); 1377 nanSymbol_ = value; 1378 } 1379 1380 /** 1381 * $(I Property.) Retrieves the string representing negative infinity. 1382 * Returns: The string representing negative infinity. For example, "-Infinity". 1383 */ 1384 @property public const final const(char)[] negativeInfinitySymbol() { 1385 return negativeInfinitySymbol_; 1386 } 1387 /** 1388 * $(I Property.) Assigns the string representing negative infinity. 1389 * Params: value = The string representing negative infinity. 1390 */ 1391 @property public final void negativeInfinitySymbol(const(char)[] value) { 1392 checkReadOnly(); 1393 negativeInfinitySymbol_ = value; 1394 } 1395 1396 /** 1397 * $(I Property.) Retrieves the string representing positive infinity. 1398 * Returns: The string representing positive infinity. For example, "Infinity". 1399 */ 1400 @property public const final const(char)[] positiveInfinitySymbol() { 1401 return positiveInfinitySymbol_; 1402 } 1403 /** 1404 * $(I Property.) Assigns the string representing positive infinity. 1405 * Params: value = The string representing positive infinity. 1406 */ 1407 @property public final void positiveInfinitySymbol(const(char)[] value) { 1408 checkReadOnly(); 1409 positiveInfinitySymbol_ = value; 1410 } 1411 1412 /** 1413 * $(I Property.) Retrieves a string array of native equivalents of the digits 0 to 9. 1414 * Returns: A string array of native equivalents of the digits 0 to 9. 1415 */ 1416 @property public const final const(char[])[] nativeDigits() { 1417 return nativeDigits_; 1418 } 1419 /** 1420 * $(I Property.) Assigns a string array of native equivalents of the digits 0 to 9. 1421 * Params: value = A string array of native equivalents of the digits 0 to 9. 1422 */ 1423 @property public final void nativeDigits(const(char[])[] value) { 1424 checkReadOnly(); 1425 nativeDigits_ = value; 1426 } 1427 1428 @property private const void checkReadOnly() { 1429 if (isReadOnly_) 1430 error("NumberFormat instance is read-only."); 1431 } 1432 1433 } 1434 1435 /** 1436 * $(ANCHOR _DateTimeFormat) 1437 * Determines how $(LINK2 #Time, Time) values are formatted, depending on the culture. 1438 * Remarks: To create a DateTimeFormat for a specific culture, create a $(LINK2 #Culture, Culture) for that culture and 1439 * retrieve its $(LINK2 #Culture_dateTimeFormat, dateTimeFormat) property. To create a DateTimeFormat for the user's current 1440 * culture, use the $(LINK2 #Culture_current, current) property. 1441 */ 1442 public class DateTimeFormat : IFormatService { 1443 1444 private __gshared immutable const(char)[] rfc1123Pattern_ = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"; 1445 private __gshared immutable const(char)[] sortableDateTimePattern_ = "yyyy'-'MM'-'dd'T'HH':'mm':'ss"; 1446 private __gshared immutable const(char)[] universalSortableDateTimePattern_ = "yyyy'-'MM'-'dd' 'HH':'mm':'ss'Z'"; 1447 private __gshared immutable const(char)[] allStandardFormats = [ 'd', 'D', 'f', 'F', 'g', 'G', 'm', 'M', 'r', 'R', 's', 't', 'T', 'u', 'U', 'y', 'Y' ]; 1448 1449 1450 package bool isReadOnly_; 1451 private __gshared DateTimeFormat invariantFormat_; 1452 private const(CultureData)* cultureData_; 1453 1454 private Calendar calendar_; 1455 private const(int)[] optionalCalendars_; 1456 private int firstDayOfWeek_ = -1; 1457 private int calendarWeekRule_ = -1; 1458 private const(char)[] dateSeparator_; 1459 private const(char)[] timeSeparator_; 1460 private const(char)[] amDesignator_; 1461 private const(char)[] pmDesignator_; 1462 private const(char)[] shortDatePattern_; 1463 private const(char)[] shortTimePattern_; 1464 private const(char)[] longDatePattern_; 1465 private const(char)[] longTimePattern_; 1466 private const(char)[] monthDayPattern_; 1467 private const(char)[] yearMonthPattern_; 1468 private const(char[])[] abbreviatedDayNames_; 1469 private const(char[])[] dayNames_; 1470 private const(char[])[] abbreviatedMonthNames_; 1471 private const(char[])[] monthNames_; 1472 1473 private const(char)[] fullDateTimePattern_; 1474 private const(char)[] generalShortTimePattern_; 1475 private const(char)[] generalLongTimePattern_; 1476 1477 private const(char[])[] shortTimePatterns_; 1478 private const(char[])[] shortDatePatterns_; 1479 private const(char[])[] longTimePatterns_; 1480 private const(char[])[] longDatePatterns_; 1481 private const(char[])[] yearMonthPatterns_; 1482 1483 /** 1484 * $(ANCHOR DateTimeFormat_ctor) 1485 * Initializes an instance that is writable and culture-independent. 1486 */ 1487 package this() { 1488 // This ctor is used by invariantFormat so we can't set the calendar property. 1489 cultureData_ = Culture.invariantCulture.cultureData_; 1490 calendar_ = Gregorian.generic; 1491 initialize(); 1492 } 1493 1494 package this(const(CultureData)* cultureData, Calendar calendar) { 1495 cultureData_ = cultureData; 1496 this.calendar = calendar; 1497 } 1498 1499 /** 1500 * $(ANCHOR DateTimeFormat_getFormat) 1501 * Retrieves an object defining how to format the specified type. 1502 * Params: type = The TypeInfo of the resulting formatting object. 1503 * Returns: If type is typeid(DateTimeFormat), the current DateTimeFormat instance. Otherwise, null. 1504 * Remarks: Implements $(LINK2 #IFormatService_getFormat, IFormatService.getFormat). 1505 */ 1506 public Object getFormat(TypeInfo type) { 1507 return (type is typeid(DateTimeFormat)) ? this : null; 1508 } 1509 1510 version(Clone) 1511 { 1512 /** 1513 */ 1514 public Object clone() { 1515 DateTimeFormat other = cast(DateTimeFormat)cloneObject(this); 1516 other.calendar_ = cast(Calendar)calendar.clone(); 1517 other.isReadOnly_ = false; 1518 return other; 1519 } 1520 } 1521 1522 @property package const(char)[][] shortTimePatterns() { 1523 if (shortTimePatterns_ is null) 1524 shortTimePatterns_ = cultureData_.shortTimes; 1525 return shortTimePatterns_.dup; 1526 } 1527 1528 @property package const(char)[][] shortDatePatterns() { 1529 if (shortDatePatterns_ is null) 1530 shortDatePatterns_ = cultureData_.shortDates; 1531 return shortDatePatterns_.dup; 1532 } 1533 1534 @property package const(char)[][] longTimePatterns() { 1535 if (longTimePatterns_ is null) 1536 longTimePatterns_ = cultureData_.longTimes; 1537 return longTimePatterns_.dup; 1538 } 1539 1540 @property package const(char)[][] longDatePatterns() { 1541 if (longDatePatterns_ is null) 1542 longDatePatterns_ = cultureData_.longDates; 1543 return longDatePatterns_.dup; 1544 } 1545 1546 @property package const(char[])[] yearMonthPatterns() { 1547 if (yearMonthPatterns_ is null) 1548 yearMonthPatterns_ = cultureData_.yearMonths; 1549 return yearMonthPatterns_; 1550 } 1551 1552 /** 1553 * $(ANCHOR DateTimeFormat_getAllDateTimePatterns) 1554 * Retrieves the standard patterns in which Time values can be formatted. 1555 * Returns: An array of strings containing the standard patterns in which Time values can be formatted. 1556 */ 1557 public final const(char)[][] getAllDateTimePatterns() { 1558 const(char)[][] result; 1559 foreach (char format; DateTimeFormat.allStandardFormats) 1560 result ~= getAllDateTimePatterns(format); 1561 return result; 1562 } 1563 1564 /** 1565 * $(ANCHOR DateTimeFormat_getAllDateTimePatterns_char) 1566 * Retrieves the standard patterns in which Time values can be formatted using the specified format character. 1567 * Returns: An array of strings containing the standard patterns in which Time values can be formatted using the specified format character. 1568 */ 1569 public final const(char)[][] getAllDateTimePatterns(char format) { 1570 1571 const(char)[][] combinePatterns(const(char)[][] patterns1, const(char)[][] patterns2) { 1572 const(char)[][] result = new const(char)[][patterns1.length * patterns2.length]; 1573 for (int i = 0; i < patterns1.length; i++) { 1574 for (int j = 0; j < patterns2.length; j++) 1575 result[i * patterns2.length + j] = patterns1[i] ~ " " ~ patterns2[j]; 1576 } 1577 return result; 1578 } 1579 1580 // format must be one of allStandardFormats. 1581 const(char)[][] result; 1582 switch (format) { 1583 case 'd': 1584 result ~= shortDatePatterns; 1585 break; 1586 case 'D': 1587 result ~= longDatePatterns; 1588 break; 1589 case 'f': 1590 result ~= combinePatterns(longDatePatterns, shortTimePatterns); 1591 break; 1592 case 'F': 1593 result ~= combinePatterns(longDatePatterns, longTimePatterns); 1594 break; 1595 case 'g': 1596 result ~= combinePatterns(shortDatePatterns, shortTimePatterns); 1597 break; 1598 case 'G': 1599 result ~= combinePatterns(shortDatePatterns, longTimePatterns); 1600 break; 1601 case 'm': 1602 case 'M': 1603 result ~= monthDayPattern; 1604 break; 1605 case 'r': 1606 case 'R': 1607 result ~= rfc1123Pattern_; 1608 break; 1609 case 's': 1610 result ~= sortableDateTimePattern_; 1611 break; 1612 case 't': 1613 result ~= shortTimePatterns; 1614 break; 1615 case 'T': 1616 result ~= longTimePatterns; 1617 break; 1618 case 'u': 1619 result ~= universalSortableDateTimePattern_; 1620 break; 1621 case 'U': 1622 result ~= combinePatterns(longDatePatterns, longTimePatterns); 1623 break; 1624 case 'y': 1625 case 'Y': 1626 result ~= yearMonthPatterns; 1627 break; 1628 default: 1629 error("The specified format was not valid."); 1630 } 1631 return result; 1632 } 1633 1634 /** 1635 * $(ANCHOR DateTimeFormat_getAbbreviatedDayName) 1636 * Retrieves the abbreviated name of the specified day of the week based on the culture of the instance. 1637 * Params: dayOfWeek = A DayOfWeek value. 1638 * Returns: The abbreviated name of the day of the week represented by dayOfWeek. 1639 */ 1640 public final const(char)[] getAbbreviatedDayName(Calendar.DayOfWeek dayOfWeek) { 1641 return abbreviatedDayNames[cast(int)dayOfWeek]; 1642 } 1643 1644 /** 1645 * $(ANCHOR DateTimeFormat_getDayName) 1646 * Retrieves the full name of the specified day of the week based on the culture of the instance. 1647 * Params: dayOfWeek = A DayOfWeek value. 1648 * Returns: The full name of the day of the week represented by dayOfWeek. 1649 */ 1650 public final const(char)[] getDayName(Calendar.DayOfWeek dayOfWeek) { 1651 return dayNames[cast(int)dayOfWeek]; 1652 } 1653 1654 /** 1655 * $(ANCHOR DateTimeFormat_getAbbreviatedMonthName) 1656 * Retrieves the abbreviated name of the specified month based on the culture of the instance. 1657 * Params: month = An integer between 1 and 13 indicating the name of the _month to return. 1658 * Returns: The abbreviated name of the _month represented by month. 1659 */ 1660 public final const(char)[] getAbbreviatedMonthName(int month) { 1661 return abbreviatedMonthNames[month - 1]; 1662 } 1663 1664 /** 1665 * $(ANCHOR DateTimeFormat_getMonthName) 1666 * Retrieves the full name of the specified month based on the culture of the instance. 1667 * Params: month = An integer between 1 and 13 indicating the name of the _month to return. 1668 * Returns: The full name of the _month represented by month. 1669 */ 1670 public final const(char)[] getMonthName(int month) { 1671 return monthNames[month - 1]; 1672 } 1673 1674 /** 1675 * $(ANCHOR DateTimeFormat_getInstance) 1676 * Retrieves the DateTimeFormat for the specified IFormatService. 1677 * Params: formatService = The IFormatService used to retrieve DateTimeFormat. 1678 * Returns: The DateTimeFormat for the specified IFormatService. 1679 * Remarks: The method calls $(LINK2 #IFormatService_getFormat, IFormatService.getFormat) with typeof(DateTimeFormat). If formatService is null, 1680 * then the value of the current property is returned. 1681 */ 1682 public static DateTimeFormat getInstance(IFormatService formatService) { 1683 Culture culture = cast(Culture)formatService; 1684 if (culture !is null) { 1685 if (culture.dateTimeFormat_ !is null) 1686 return culture.dateTimeFormat_; 1687 return culture.dateTimeFormat; 1688 } 1689 if (DateTimeFormat dateTimeFormat = cast(DateTimeFormat)formatService) 1690 return dateTimeFormat; 1691 if (formatService !is null) { 1692 if (DateTimeFormat dateTimeFormat = cast(DateTimeFormat)(formatService.getFormat(typeid(DateTimeFormat)))) 1693 return dateTimeFormat; 1694 } 1695 return current; 1696 } 1697 1698 /** 1699 * $(ANCHOR DateTimeFormat_current) 1700 * $(I Property.) Retrieves a read-only DateTimeFormat instance from the current culture. 1701 * Returns: A read-only DateTimeFormat instance from the current culture. 1702 */ 1703 @property public static DateTimeFormat current() { 1704 return Culture.current.dateTimeFormat; 1705 } 1706 1707 /** 1708 * $(ANCHOR DateTimeFormat_invariantFormat) 1709 * $(I Property.) Retrieves a read-only DateTimeFormat instance that is culturally independent. 1710 * Returns: A read-only DateTimeFormat instance that is culturally independent. 1711 */ 1712 public static DateTimeFormat invariantFormat() { 1713 if (invariantFormat_ is null) { 1714 invariantFormat_ = new DateTimeFormat; 1715 invariantFormat_.calendar = new Gregorian(); 1716 invariantFormat_.isReadOnly_ = true; 1717 } 1718 return invariantFormat_; 1719 } 1720 1721 /** 1722 * $(ANCHOR DateTimeFormat_isReadOnly) 1723 * $(I Property.) Retrieves a value indicating whether the instance is read-only. 1724 * Returns: true is the instance is read-only; otherwise, false. 1725 */ 1726 @property public final bool isReadOnly() { 1727 return isReadOnly_; 1728 } 1729 1730 /** 1731 * $(I Property.) Retrieves the calendar used by the current culture. 1732 * Returns: The Calendar determining the calendar used by the current culture. For example, the Gregorian. 1733 */ 1734 @property public final Calendar calendar() { 1735 assert(calendar_ !is null); 1736 return calendar_; 1737 } 1738 /** 1739 * $(ANCHOR DateTimeFormat_calendar) 1740 * $(I Property.) Assigns the calendar to be used by the current culture. 1741 * Params: value = The Calendar determining the calendar to be used by the current culture. 1742 * Exceptions: If value is not valid for the current culture, an Exception is thrown. 1743 */ 1744 @property public final void calendar(Calendar value) { 1745 checkReadOnly(); 1746 if (value !is calendar_) { 1747 for (int i = 0; i < optionalCalendars.length; i++) { 1748 if (optionalCalendars[i] == value.id) { 1749 if (calendar_ !is null) { 1750 // Clear current properties. 1751 shortDatePattern_ = null; 1752 longDatePattern_ = null; 1753 shortTimePattern_ = null; 1754 yearMonthPattern_ = null; 1755 monthDayPattern_ = null; 1756 generalShortTimePattern_ = null; 1757 generalLongTimePattern_ = null; 1758 fullDateTimePattern_ = null; 1759 shortDatePatterns_ = null; 1760 longDatePatterns_ = null; 1761 yearMonthPatterns_ = null; 1762 abbreviatedDayNames_ = null; 1763 abbreviatedMonthNames_ = null; 1764 dayNames_ = null; 1765 monthNames_ = null; 1766 } 1767 calendar_ = value; 1768 initialize(); 1769 return; 1770 } 1771 } 1772 error("Not a valid calendar for the culture."); 1773 } 1774 } 1775 1776 /** 1777 * $(ANCHOR DateTimeFormat_firstDayOfWeek) 1778 * $(I Property.) Retrieves the first day of the week. 1779 * Returns: A DayOfWeek value indicating the first day of the week. 1780 */ 1781 @property public final Calendar.DayOfWeek firstDayOfWeek() { 1782 return cast(Calendar.DayOfWeek)firstDayOfWeek_; 1783 } 1784 /** 1785 * $(I Property.) Assigns the first day of the week. 1786 * Params: valie = A DayOfWeek value indicating the first day of the week. 1787 */ 1788 @property public final void firstDayOfWeek(Calendar.DayOfWeek value) { 1789 checkReadOnly(); 1790 firstDayOfWeek_ = value; 1791 } 1792 1793 /** 1794 * $(ANCHOR DateTimeFormat_calendarWeekRule) 1795 * $(I Property.) Retrieves the _value indicating the rule used to determine the first week of the year. 1796 * Returns: A CalendarWeekRule _value determining the first week of the year. 1797 */ 1798 @property public final Calendar.WeekRule calendarWeekRule() { 1799 return cast(Calendar.WeekRule) calendarWeekRule_; 1800 } 1801 /** 1802 * $(I Property.) Assigns the _value indicating the rule used to determine the first week of the year. 1803 * Params: value = A CalendarWeekRule _value determining the first week of the year. 1804 */ 1805 @property public final void calendarWeekRule(Calendar.WeekRule value) { 1806 checkReadOnly(); 1807 calendarWeekRule_ = value; 1808 } 1809 1810 /** 1811 * $(ANCHOR DateTimeFormat_nativeCalendarName) 1812 * $(I Property.) Retrieves the native name of the calendar associated with the current instance. 1813 * Returns: The native name of the calendar associated with the current instance. 1814 */ 1815 @property public final const(char)[] nativeCalendarName() { 1816 return cultureData_.nativeCalName; 1817 } 1818 1819 /** 1820 * $(ANCHOR DateTimeFormat_dateSeparator) 1821 * $(I Property.) Retrieves the string separating date components. 1822 * Returns: The string separating date components. 1823 */ 1824 @property public final const(char)[] dateSeparator() { 1825 if (dateSeparator_ is null) 1826 dateSeparator_ = cultureData_.date; 1827 return dateSeparator_; 1828 } 1829 /** 1830 * $(I Property.) Assigns the string separating date components. 1831 * Params: value = The string separating date components. 1832 */ 1833 @property public final void dateSeparator(const(char)[] value) { 1834 checkReadOnly(); 1835 dateSeparator_ = value; 1836 } 1837 1838 /** 1839 * $(ANCHOR DateTimeFormat_timeSeparator) 1840 * $(I Property.) Retrieves the string separating time components. 1841 * Returns: The string separating time components. 1842 */ 1843 @property public final const(char)[] timeSeparator() { 1844 if (timeSeparator_ is null) 1845 timeSeparator_ = cultureData_.time; 1846 return timeSeparator_; 1847 } 1848 /** 1849 * $(I Property.) Assigns the string separating time components. 1850 * Params: value = The string separating time components. 1851 */ 1852 @property public final void timeSeparator(const(char)[] value) { 1853 checkReadOnly(); 1854 timeSeparator_ = value; 1855 } 1856 1857 /** 1858 * $(ANCHOR DateTimeFormat_amDesignator) 1859 * $(I Property.) Retrieves the string designator for hours before noon. 1860 * Returns: The string designator for hours before noon. For example, "AM". 1861 */ 1862 @property public final const(char)[] amDesignator() { 1863 assert(amDesignator_ !is null); 1864 return amDesignator_; 1865 } 1866 /** 1867 * $(I Property.) Assigns the string designator for hours before noon. 1868 * Params: value = The string designator for hours before noon. 1869 */ 1870 @property public final void amDesignator(const(char)[] value) { 1871 checkReadOnly(); 1872 amDesignator_ = value; 1873 } 1874 1875 /** 1876 * $(ANCHOR DateTimeFormat_pmDesignator) 1877 * $(I Property.) Retrieves the string designator for hours after noon. 1878 * Returns: The string designator for hours after noon. For example, "PM". 1879 */ 1880 @property public final const(char)[] pmDesignator() { 1881 assert(pmDesignator_ !is null); 1882 return pmDesignator_; 1883 } 1884 /** 1885 * $(I Property.) Assigns the string designator for hours after noon. 1886 * Params: value = The string designator for hours after noon. 1887 */ 1888 @property public final void pmDesignator(const(char)[] value) { 1889 checkReadOnly(); 1890 pmDesignator_ = value; 1891 } 1892 1893 /** 1894 * $(ANCHOR DateTimeFormat_shortDatePattern) 1895 * $(I Property.) Retrieves the format pattern for a short date value. 1896 * Returns: The format pattern for a short date value. 1897 */ 1898 @property public final const(char)[] shortDatePattern() { 1899 assert(shortDatePattern_ !is null); 1900 return shortDatePattern_; 1901 } 1902 /** 1903 * $(I Property.) Assigns the format pattern for a short date _value. 1904 * Params: value = The format pattern for a short date _value. 1905 */ 1906 @property public final void shortDatePattern(const(char)[] value) { 1907 checkReadOnly(); 1908 if (shortDatePatterns_ !is null) 1909 shortDatePatterns_ = [value]; 1910 shortDatePattern_ = value; 1911 generalLongTimePattern_ = null; 1912 generalShortTimePattern_ = null; 1913 } 1914 1915 /** 1916 * $(ANCHOR DateTimeFormat_shortTimePattern) 1917 * $(I Property.) Retrieves the format pattern for a short time value. 1918 * Returns: The format pattern for a short time value. 1919 */ 1920 @property public final const(char)[] shortTimePattern() { 1921 if (shortTimePattern_ is null) 1922 shortTimePattern_ = cultureData_.shortTime; 1923 return shortTimePattern_; 1924 } 1925 /** 1926 * $(I Property.) Assigns the format pattern for a short time _value. 1927 * Params: value = The format pattern for a short time _value. 1928 */ 1929 @property public final void shortTimePattern(const(char)[] value) { 1930 checkReadOnly(); 1931 shortTimePattern_ = value; 1932 generalShortTimePattern_ = null; 1933 } 1934 1935 /** 1936 * $(ANCHOR DateTimeFormat_longDatePattern) 1937 * $(I Property.) Retrieves the format pattern for a long date value. 1938 * Returns: The format pattern for a long date value. 1939 */ 1940 @property public final const(char)[] longDatePattern() { 1941 assert(longDatePattern_ !is null); 1942 return longDatePattern_; 1943 } 1944 /** 1945 * $(I Property.) Assigns the format pattern for a long date _value. 1946 * Params: value = The format pattern for a long date _value. 1947 */ 1948 @property public final void longDatePattern(const(char)[] value) { 1949 checkReadOnly(); 1950 if (longDatePatterns_ !is null) 1951 longDatePatterns_ = [value]; 1952 longDatePattern_ = value; 1953 fullDateTimePattern_ = null; 1954 } 1955 1956 /** 1957 * $(ANCHOR DateTimeFormat_longTimePattern) 1958 * $(I Property.) Retrieves the format pattern for a long time value. 1959 * Returns: The format pattern for a long time value. 1960 */ 1961 @property public final const(char)[] longTimePattern() { 1962 assert(longTimePattern_ !is null); 1963 return longTimePattern_; 1964 } 1965 /** 1966 * $(I Property.) Assigns the format pattern for a long time _value. 1967 * Params: value = The format pattern for a long time _value. 1968 */ 1969 @property public final void longTimePattern(const(char)[] value) { 1970 checkReadOnly(); 1971 longTimePattern_ = value; 1972 fullDateTimePattern_ = null; 1973 } 1974 1975 /** 1976 * $(ANCHOR DateTimeFormat_monthDayPattern) 1977 * $(I Property.) Retrieves the format pattern for a month and day value. 1978 * Returns: The format pattern for a month and day value. 1979 */ 1980 @property public final const(char)[] monthDayPattern() { 1981 if (monthDayPattern_ is null) 1982 monthDayPattern_ = cultureData_.monthDay; 1983 return monthDayPattern_; 1984 } 1985 /** 1986 * $(I Property.) Assigns the format pattern for a month and day _value. 1987 * Params: value = The format pattern for a month and day _value. 1988 */ 1989 @property public final void monthDayPattern(const(char)[] value) { 1990 checkReadOnly(); 1991 monthDayPattern_ = value; 1992 } 1993 1994 /** 1995 * $(ANCHOR DateTimeFormat_yearMonthPattern) 1996 * $(I Property.) Retrieves the format pattern for a year and month value. 1997 * Returns: The format pattern for a year and month value. 1998 */ 1999 @property public final const(char)[] yearMonthPattern() { 2000 assert(yearMonthPattern_ !is null); 2001 return yearMonthPattern_; 2002 } 2003 /** 2004 * $(I Property.) Assigns the format pattern for a year and month _value. 2005 * Params: value = The format pattern for a year and month _value. 2006 */ 2007 @property public final void yearMonthPattern(const(char)[] value) { 2008 checkReadOnly(); 2009 yearMonthPattern_ = value; 2010 } 2011 2012 /** 2013 * $(ANCHOR DateTimeFormat_abbreviatedDayNames) 2014 * $(I Property.) Retrieves a string array containing the abbreviated names of the days of the week. 2015 * Returns: A string array containing the abbreviated names of the days of the week. For $(LINK2 #DateTimeFormat_invariantFormat, invariantFormat), 2016 * this contains "Sun", "Mon", "Tue", "Wed", "Thu", "Fri" and "Sat". 2017 */ 2018 @property public final const(char)[][] abbreviatedDayNames() { 2019 if (abbreviatedDayNames_ is null) 2020 abbreviatedDayNames_ = cultureData_.abbrevDayNames; 2021 return abbreviatedDayNames_.dup; 2022 } 2023 /** 2024 * $(I Property.) Assigns a string array containing the abbreviated names of the days of the week. 2025 * Params: value = A string array containing the abbreviated names of the days of the week. 2026 */ 2027 @property public final void abbreviatedDayNames(const(char)[][] value) { 2028 checkReadOnly(); 2029 abbreviatedDayNames_ = value; 2030 } 2031 2032 /** 2033 * $(ANCHOR DateTimeFormat_dayNames) 2034 * $(I Property.) Retrieves a string array containing the full names of the days of the week. 2035 * Returns: A string array containing the full names of the days of the week. For $(LINK2 #DateTimeFormat_invariantFormat, invariantFormat), 2036 * this contains "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" and "Saturday". 2037 */ 2038 @property public final const(char)[][] dayNames() { 2039 if (dayNames_ is null) 2040 dayNames_ = cultureData_.dayNames; 2041 return dayNames_.dup; 2042 } 2043 /** 2044 * $(I Property.) Assigns a string array containing the full names of the days of the week. 2045 * Params: value = A string array containing the full names of the days of the week. 2046 */ 2047 @property public final void dayNames(const(char)[][] value) { 2048 checkReadOnly(); 2049 dayNames_ = value; 2050 } 2051 2052 /** 2053 * $(ANCHOR DateTimeFormat_abbreviatedMonthNames) 2054 * $(I Property.) Retrieves a string array containing the abbreviated names of the months. 2055 * Returns: A string array containing the abbreviated names of the months. For $(LINK2 #DateTimeFormat_invariantFormat, invariantFormat), 2056 * this contains "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" and "". 2057 */ 2058 @property public final const(char)[][] abbreviatedMonthNames() { 2059 if (abbreviatedMonthNames_ is null) 2060 abbreviatedMonthNames_ = cultureData_.abbrevMonthNames; 2061 return abbreviatedMonthNames_.dup; 2062 } 2063 /** 2064 * $(I Property.) Assigns a string array containing the abbreviated names of the months. 2065 * Params: value = A string array containing the abbreviated names of the months. 2066 */ 2067 @property public final void abbreviatedMonthNames(const(char)[][] value) { 2068 checkReadOnly(); 2069 abbreviatedMonthNames_ = value; 2070 } 2071 2072 /** 2073 * $(ANCHOR DateTimeFormat_monthNames) 2074 * $(I Property.) Retrieves a string array containing the full names of the months. 2075 * Returns: A string array containing the full names of the months. For $(LINK2 #DateTimeFormat_invariantFormat, invariantFormat), 2076 * this contains "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" and "". 2077 */ 2078 @property public final const(char)[][] monthNames() { 2079 if (monthNames_ is null) 2080 monthNames_ = cultureData_.monthNames; 2081 return monthNames_.dup; 2082 } 2083 /** 2084 * $(I Property.) Assigns a string array containing the full names of the months. 2085 * Params: value = A string array containing the full names of the months. 2086 */ 2087 @property public final void monthNames(const(char)[][] value) { 2088 checkReadOnly(); 2089 monthNames_ = value; 2090 } 2091 2092 /** 2093 * $(ANCHOR DateTimeFormat_fullDateTimePattern) 2094 * $(I Property.) Retrieves the format pattern for a long date and a long time value. 2095 * Returns: The format pattern for a long date and a long time value. 2096 */ 2097 @property public final const(char)[] fullDateTimePattern() { 2098 if (fullDateTimePattern_ is null) 2099 fullDateTimePattern_ = longDatePattern ~ " " ~ longTimePattern; 2100 return fullDateTimePattern_; 2101 } 2102 /** 2103 * $(I Property.) Assigns the format pattern for a long date and a long time _value. 2104 * Params: value = The format pattern for a long date and a long time _value. 2105 */ 2106 @property public final void fullDateTimePattern(const(char)[] value) { 2107 checkReadOnly(); 2108 fullDateTimePattern_ = value; 2109 } 2110 2111 /** 2112 * $(ANCHOR DateTimeFormat_rfc1123Pattern) 2113 * $(I Property.) Retrieves the format pattern based on the IETF RFC 1123 specification, for a time value. 2114 * Returns: The format pattern based on the IETF RFC 1123 specification, for a time value. 2115 */ 2116 @property public const final const(char)[] rfc1123Pattern() { 2117 return rfc1123Pattern_; 2118 } 2119 2120 /** 2121 * $(ANCHOR DateTimeFormat_sortableDateTimePattern) 2122 * $(I Property.) Retrieves the format pattern for a sortable date and time value. 2123 * Returns: The format pattern for a sortable date and time value. 2124 */ 2125 @property public const final const(char)[] sortableDateTimePattern() { 2126 return sortableDateTimePattern_; 2127 } 2128 2129 /** 2130 * $(ANCHOR DateTimeFormat_universalSortableDateTimePattern) 2131 * $(I Property.) Retrieves the format pattern for a universal date and time value. 2132 * Returns: The format pattern for a universal date and time value. 2133 */ 2134 @property public const final const(char)[] universalSortableDateTimePattern() { 2135 return universalSortableDateTimePattern_; 2136 } 2137 2138 @property package const(char)[] generalShortTimePattern() { 2139 if (generalShortTimePattern_ is null) 2140 generalShortTimePattern_ = shortDatePattern ~ " " ~ shortTimePattern; 2141 return generalShortTimePattern_; 2142 } 2143 2144 @property package const(char)[] generalLongTimePattern() { 2145 if (generalLongTimePattern_ is null) 2146 generalLongTimePattern_ = shortDatePattern ~ " " ~ longTimePattern; 2147 return generalLongTimePattern_; 2148 } 2149 2150 @property private const void checkReadOnly() { 2151 if (isReadOnly_) 2152 error("DateTimeFormat instance is read-only."); 2153 } 2154 2155 private void initialize() { 2156 if (longTimePattern_ is null) 2157 longTimePattern_ = cultureData_.longTime; 2158 if (shortDatePattern_ is null) 2159 shortDatePattern_ = cultureData_.shortDate; 2160 if (longDatePattern_ is null) 2161 longDatePattern_ = cultureData_.longDate; 2162 if (yearMonthPattern_ is null) 2163 yearMonthPattern_ = cultureData_.yearMonth; 2164 if (amDesignator_ is null) 2165 amDesignator_ = cultureData_.am; 2166 if (pmDesignator_ is null) 2167 pmDesignator_ = cultureData_.pm; 2168 if (firstDayOfWeek_ is -1) 2169 firstDayOfWeek_ = cultureData_.firstDayOfWeek; 2170 if (calendarWeekRule_ == -1) 2171 calendarWeekRule_ = cultureData_.firstDayOfYear; 2172 } 2173 2174 @property private const(int)[] optionalCalendars() { 2175 if (optionalCalendars_ is null) 2176 optionalCalendars_ = cultureData_.optionalCalendars; 2177 return optionalCalendars_; 2178 } 2179 2180 private const void error(immutable(char)[] msg) { 2181 throw new LocaleException (msg); 2182 } 2183 2184 } 2185 2186