Enumerates all the era names of the specified locale and calendar, invoking the callback function
for each era name.
*/
-bool EnumEraNames(Locale& locale, CalendarId calendarId, EnumCalendarInfoCallback callback, const void* context)
+bool EnumEraNames(Locale& locale, CalendarId calendarId, CalendarDataType dataType, EnumCalendarInfoCallback callback, const void* context)
{
UErrorCode err = U_ZERO_ERROR;
- DateFormatSymbols dateFormatSymbols(locale, GetCalendarName(calendarId), err);
+ const char* calendarName = GetCalendarName(calendarId);
+ DateFormatSymbols dateFormatSymbols(locale, calendarName, err);
if (U_FAILURE(err))
return false;
int32_t eraNameCount;
- const UnicodeString* eraNames = dateFormatSymbols.getEras(eraNameCount);
+ const UnicodeString* eraNames;
+
+ if (dataType == EraNames)
+ {
+ eraNames = dateFormatSymbols.getEras(eraNameCount);
+ }
+ else if (dataType == AbbrevEraNames)
+ {
+ if (strcmp(calendarName, "gregorian") == 0)
+ {
+ // NOTE: On Windows, the EraName is "A.D." and AbbrevEraName is "AD".
+ // But ICU/CLDR only supports "Anno Domini", "AD", and "A".
+ // So returning getEras (i.e. "AD") for both EraNames and AbbrevEraNames.
+ eraNames = dateFormatSymbols.getEras(eraNameCount);
+ }
+ else
+ {
+ eraNames = dateFormatSymbols.getNarrowEras(eraNameCount);
+ }
+ }
+ else
+ {
+ assert(false);
+ return false;
+ }
+
return EnumCalendarArray(eraNames, eraNameCount, callback, context);
}
case LongDates:
// TODO: need to replace the "EEEE"s with "dddd"s for .net
// Also, "LLLL"s to "MMMM"s
+ // Also, "G"s to "g"s
return InvokeCallbackForDateTimePattern(locale, "eeeeMMMMddyyyy", callback, context);
case YearMonths:
return InvokeCallbackForDateTimePattern(locale, "yyyyMMMM", callback, context);
return EnumMonths(locale, calendarId, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED, callback, context);
case EraNames:
case AbbrevEraNames:
- // NOTE: On Windows, the EraName is "A.D." and AbbrevEraName is "AD".
- // But ICU/CLDR only supports "Anno Domini", "AD", and "A".
- // So returning getEras (i.e. "AD") for both EraNames and AbbrevEraNames.
- return EnumEraNames(locale, calendarId, callback, context);
+ return EnumEraNames(locale, calendarId, dataType, callback, context);
default:
assert(false);
return false;
}
}
+
+/*
+Function:
+GetLatestJapaneseEra
+
+Gets the latest era in the Japanese calendar.
+*/
+extern "C" int32_t GetLatestJapaneseEra()
+{
+ UErrorCode err = U_ZERO_ERROR;
+ Locale japaneseLocale("ja_JP@calendar=japanese");
+ LocalPointer<Calendar> calendar(Calendar::createInstance(japaneseLocale, err));
+
+ if (U_FAILURE(err))
+ return 0;
+
+ return calendar->getMaximum(UCAL_ERA);
+}
+
+/*
+Function:
+GetJapaneseEraInfo
+
+Gets the starting Gregorian date of the specified Japanese Era.
+*/
+extern "C" int32_t GetJapaneseEraStartDate(
+ int32_t era,
+ int32_t* startYear,
+ int32_t* startMonth,
+ int32_t* startDay)
+{
+ UErrorCode err = U_ZERO_ERROR;
+ Locale japaneseLocale("ja_JP@calendar=japanese");
+ LocalPointer<Calendar> calendar(Calendar::createInstance(japaneseLocale, err));
+ if (U_FAILURE(err))
+ return false;
+
+ calendar->set(UCAL_ERA, era);
+ calendar->set(UCAL_YEAR, 1);
+
+ // UCAL_EXTENDED_YEAR is the gregorian year for the JapaneseCalendar
+ *startYear = calendar->get(UCAL_EXTENDED_YEAR, err);
+ if (U_FAILURE(err))
+ return false;
+
+ // set the date to Jan 1
+ calendar->set(UCAL_MONTH, 0);
+ calendar->set(UCAL_DATE, 1);
+
+ int32_t currentEra = calendar->get(UCAL_ERA, err);
+ if (U_FAILURE(err))
+ return false;
+
+ if (currentEra == era)
+ {
+ // if Jan 1 is still in the specified Era, then the Era must have started on Jan 1.
+ *startMonth = 1;
+ *startDay = 1;
+ return true;
+ }
+
+ for (int i = 0; i < 12; i++)
+ {
+ // add 1 month at a time until we get into the specified Era
+ calendar->add(UCAL_MONTH, 1, err);
+ if (U_FAILURE(err))
+ return false;
+
+ currentEra = calendar->get(UCAL_ERA, err);
+ if (U_FAILURE(err))
+ return false;
+
+ if (currentEra == era)
+ {
+ for (int i = 0; i < 32; i++)
+ {
+ // now subtract 1 day at a time until we get out of the specified Era
+ calendar->add(Calendar::DATE, -1, err);
+ if (U_FAILURE(err))
+ return false;
+
+ currentEra = calendar->get(UCAL_ERA, err);
+ if (U_FAILURE(err))
+ return false;
+
+ if (currentEra != era)
+ {
+ // add back 1 day to get back into the specified Era
+ calendar->add(UCAL_DATE, 1, err);
+ if (U_FAILURE(err))
+ return false;
+
+ *startMonth = calendar->get(UCAL_MONTH, err) + 1; // ICU Calendar months are 0-based, but .NET is 1-based
+ if (U_FAILURE(err))
+ return false;
+
+ *startDay = calendar->get(UCAL_DATE, err);
+ if (U_FAILURE(err))
+ return false;
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
[DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumCalendarInfo(EnumCalendarInfoCallback callback, string localeName, CalendarId calendarId, CalendarDataType calendarDataType, IntPtr context);
+
+ [DllImport(Libraries.GlobalizationInterop)]
+ internal static extern int GetLatestJapaneseEra();
+
+ [DllImport(Libraries.GlobalizationInterop)]
+ internal static extern bool GetJapaneseEraStartDate(int era, out int startYear, out int startMonth, out int startDay);
}
}
return false;
}
- private static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] calendarData)
+ internal static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] calendarData)
{
calendarData = null;
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System.Collections.Generic;
+
namespace System.Globalization
{
public partial class JapaneseCalendar : Calendar
{
- private static int GetJapaneseEraCount()
+ private static EraInfo[] GetJapaneseEras()
{
- //UNIXTODO: Implement this fully.
- return 0;
+ string[] eraNames;
+ if (!CalendarData.EnumCalendarInfo("ja-JP", CalendarId.JAPAN, CalendarDataType.EraNames, out eraNames))
+ {
+ return null;
+ }
+
+ string[] abbrevEnglishEraNames;
+ if (!CalendarData.EnumCalendarInfo("en", CalendarId.JAPAN, CalendarDataType.AbbrevEraNames, out abbrevEnglishEraNames))
+ {
+ return null;
+ }
+
+ List<EraInfo> eras = new List<EraInfo>();
+ int lastMaxYear = GregorianCalendar.MaxYear;
+
+ int latestEra = Interop.GlobalizationInterop.GetLatestJapaneseEra();
+ for (int i = latestEra; i >= 0; i--)
+ {
+ DateTime dt;
+ if (!GetJapaneseEraStartDate(i, out dt))
+ {
+ return null;
+ }
+
+ if (dt < JapaneseCalendar.calendarMinValue)
+ {
+ // only populate the Eras that are valid JapaneseCalendar date times
+ break;
+ }
+
+ eras.Add(new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1,
+ eraNames[i], GetAbbreviatedEraName(eraNames, i), abbrevEnglishEraNames[i]));
+
+ lastMaxYear = dt.Year;
+ }
+
+ // remap the Era numbers, now that we know how many there will be
+ for (int i = 0; i < eras.Count; i++)
+ {
+ eras[i].era = eras.Count - i;
+ }
+
+ return eras.ToArray();
}
- private static bool GetJapaneseEraInfo(int era, out DateTimeOffset dateOffset, out string eraName, out string abbreviatedEraName)
+ // PAL Layer ends here
+
+ private static string GetAbbreviatedEraName(string[] eraNames, int eraIndex)
{
- //UNIXTODO: Implement this fully.
- dateOffset = default(DateTimeOffset);
- eraName = null;
- abbreviatedEraName = null;
+ // This matches the behavior on Win32 - only returning the first character of the era name.
+ // See Calendar.EraAsString(Int32) - https://msdn.microsoft.com/en-us/library/windows/apps/br206751.aspx
+ return eraNames[eraIndex].Substring(0, 1);
+ }
+
+ private static bool GetJapaneseEraStartDate(int era, out DateTime dateTime)
+ {
+ dateTime = default(DateTime);
+
+ int startYear;
+ int startMonth;
+ int startDay;
+ bool result = Interop.GlobalizationInterop.GetJapaneseEraStartDate(
+ era,
+ out startYear,
+ out startMonth,
+ out startDay);
+
+ if (result)
+ {
+ dateTime = new DateTime(startYear, startMonth, startDay);
+ }
- return false;
+ return result;
}
}
}
{
public partial class JapaneseCalendar : Calendar
{
- public static int GetJapaneseEraCount()
+ private static EraInfo[] GetJapaneseEras()
{
- return WinRTInterop.Callbacks.GetJapaneseEraCount();
+ int erasCount = WinRTInterop.Callbacks.GetJapaneseEraCount();
+ if (erasCount < 4)
+ {
+ return null;
+ }
+
+ EraInfo[] eras = new EraInfo[erasCount];
+ int lastMaxYear = GregorianCalendar.MaxYear;
+
+ for (int i = erasCount; i > 0; i--)
+ {
+ DateTimeOffset dateOffset;
+
+ string eraName;
+ string abbreviatedEraName;
+
+ if (!GetJapaneseEraInfo(i, out dateOffset, out eraName, out abbreviatedEraName))
+ {
+ return null;
+ }
+
+ DateTime dt = new DateTime(dateOffset.Ticks);
+
+ eras[erasCount - i] = new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1,
+ eraName, abbreviatedEraName, GetJapaneseEnglishEraName(i)); // era #4 start year/month/day, yearOffset, minEraYear
+
+ lastMaxYear = dt.Year;
+ }
+
+ return eras;
+ }
+
+ // PAL Layer ends here
+
+ private static string[] JapaneseErasEnglishNames = new String[] { "M", "T", "S", "H" };
+
+ private static string GetJapaneseEnglishEraName(int era)
+ {
+ Debug.Assert(era > 0);
+ return era <= JapaneseErasEnglishNames.Length ? JapaneseErasEnglishNames[era - 1] : " ";
}
- public static bool GetJapaneseEraInfo(int era, out DateTimeOffset dateOffset, out string eraName, out string abbreviatedEraName)
+ private static bool GetJapaneseEraInfo(int era, out DateTimeOffset dateOffset, out string eraName, out string abbreviatedEraName)
{
return WinRTInterop.Callbacks.GetJapaneseEraInfo(era, out dateOffset, out eraName, out abbreviatedEraName);
}
return japaneseEraInfo;
}
- private static EraInfo[] GetJapaneseEras()
- {
- int erasCount = GetJapaneseEraCount();
- if (erasCount < 4)
- {
- return null;
- }
-
- EraInfo[] eras = new EraInfo[erasCount];
- int lastMaxYear = GregorianCalendar.MaxYear;
-
- for (int i = erasCount; i > 0; i--)
- {
- DateTimeOffset dateOffset;
-
- string eraName;
- string abbreviatedEraName;
-
- if (!GetJapaneseEraInfo(i, out dateOffset, out eraName, out abbreviatedEraName))
- {
- return null;
- }
-
- DateTime dt = new DateTime(dateOffset.Ticks);
-
- eras[erasCount - i] = new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1,
- eraName, abbreviatedEraName, GetJapaneseEnglishEraName(i)); // era #4 start year/month/day, yearOffset, minEraYear
-
- lastMaxYear = dt.Year;
- }
-
- return eras;
- }
-
- private static string[] JapaneseErasEnglishNames = new String[] { "M", "T", "S", "H" };
-
- private static string GetJapaneseEnglishEraName(int era)
- {
- Debug.Assert(era > 0);
- return era <= JapaneseErasEnglishNames.Length ? JapaneseErasEnglishNames[era - 1] : " ";
- }
-
-
internal static volatile Calendar s_defaultInstance;
internal GregorianCalendarHelper helper;