/*

 * Copyright (c) 2021-2025 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

#include "date_time_format.h"

#include "ohos/init_data.h"

#include "locale_config.h"

#include "utils.h"



namespace OHOS {

namespace Global {

namespace I18n {

const char *DateTimeFormat::DEFAULT_TIMEZONE = "GMT";



using namespace icu;

bool DateTimeFormat::icuInitialized = DateTimeFormat::Init();



std::map<std::string, DateFormat::EStyle> DateTimeFormat::dateTimeStyle = {

    { "full", DateFormat::EStyle::kFull },

    { "long", DateFormat::EStyle::kLong },

    { "medium", DateFormat::EStyle::kMedium },

    { "short", DateFormat::EStyle::kShort }

};



std::unordered_map<std::string, DefaultStyle> DateTimeFormat::DeviceToStyle = {

    { "tablet", DefaultStyle::LONG },

    { "2in1", DefaultStyle::LONG },

    { "tv", DefaultStyle::LONG },

    { "pc", DefaultStyle::LONG },

    { "liteWearable", DefaultStyle::SHORT },

    { "wearable", DefaultStyle::SHORT },

    { "watch", DefaultStyle::SHORT }

};



std::unordered_map<DefaultStyle, DateFormat::EStyle> DateTimeFormat::DefaultDTStyle = {

    { DefaultStyle::LONG, DateFormat::EStyle::kMedium },

    { DefaultStyle::DEFAULT, DateFormat::EStyle::kShort },

    { DefaultStyle::SHORT, DateFormat::EStyle::kShort },

};



DateTimeFormat::DateTimeFormat(const std::vector<std::string> &localeTags, std::map<std::string, std::string> &configs)

{

    defaultStyle = GetDefaultStyle();

    UErrorCode status = U_ZERO_ERROR;

    ParseConfigsPartOne(configs);

    ParseConfigsPartTwo(configs);

    for (size_t i = 0; i < localeTags.size(); i++) {

        std::string curLocale = localeTags[i];

        locale = Locale::forLanguageTag(StringPiece(curLocale), status);

        if (status != U_ZERO_ERROR) {

            status = U_ZERO_ERROR;

            continue;

        }

        if (LocaleInfo::GetValidLocales().count(locale.getLanguage()) > 0) {

            createSuccess = InitWithLocale(curLocale, configs);

            if (!createSuccess || !dateFormat) {

                FreeDateTimeFormat();

                continue;

            }

            break;

        }

    }

    if (!localeInfo || !dateFormat) {

        createSuccess = InitWithDefaultLocale(configs);

    }

}



void DateTimeFormat::FreeDateTimeFormat()

{

    if (dateIntvFormat != nullptr) {

        delete dateIntvFormat;

        dateIntvFormat = nullptr;

    }

    if (calendar != nullptr) {

        delete calendar;

        calendar = nullptr;

    }

    if (dateFormat != nullptr) {

        delete dateFormat;

        dateFormat = nullptr;

    }

    if (localeInfo != nullptr) {

        delete localeInfo;

        localeInfo = nullptr;

    }

}



DateTimeFormat::~DateTimeFormat()

{

    FreeDateTimeFormat();

}



bool DateTimeFormat::CheckInitSuccess()

{

    if (dateIntvFormat == nullptr || calendar == nullptr || dateFormat == nullptr || localeInfo == nullptr) {

        return false;

    }

    return true;

}



std::unique_ptr<DateTimeFormat> DateTimeFormat::CreateInstance(const std::vector<std::string> &localeTags,

                                                               std::map<std::string, std::string> &configs)

{

    std::unique_ptr<DateTimeFormat> dateTimeFormat = std::make_unique<DateTimeFormat>(localeTags, configs);

    if (!dateTimeFormat->CheckInitSuccess()) {

        return nullptr;

    }

    return dateTimeFormat;

}



bool DateTimeFormat::InitWithLocale(const std::string &curLocale, std::map<std::string, std::string> &configs)

{

    localeInfo = new LocaleInfo(curLocale, configs);

    if (localeInfo == nullptr || !localeInfo->InitSuccess()) {

        return false;

    }



    locale = localeInfo->GetLocale();

    localeTag = localeInfo->GetBaseName();

    if (hourCycle.empty()) {

        hourCycle = localeInfo->GetHourCycle();

    }

    if (hour12.empty() && hourCycle.empty()) {

        bool is24HourClock = LocaleConfig::Is24HourClock();

        hour12 = is24HourClock ? "false" : "true";

    }

    ComputeHourCycleChars();

    ComputeSkeleton();

    UErrorCode status = U_ZERO_ERROR;

    if (!configs.size()) {

        InitDateFormatWithoutConfigs(status);

    } else {

        InitDateFormat(status);

    }

    if (!U_SUCCESS(status)) {

        return false;

    }

    status = U_ZERO_ERROR;

    calendar = Calendar::createInstance(locale, status);

    if (!U_SUCCESS(status)) {

        return false;

    }

    return true;

}



bool DateTimeFormat::InitWithDefaultLocale(std::map<std::string, std::string> &configs)

{

    if (localeInfo != nullptr) {

        delete localeInfo;

        localeInfo = nullptr;

    }

    if (dateFormat != nullptr) {

        delete dateFormat;

        dateFormat = nullptr;

    }



    return InitWithLocale(LocaleConfig::GetSystemLocaleWithExtParam(), configs);

}



void DateTimeFormat::InitDateFormatWithoutConfigs(UErrorCode &status)

{

    dateFormat = DateFormat::createDateInstance(DefaultDTStyle[defaultStyle], locale);

    SimpleDateFormat *simDateFormat = static_cast<SimpleDateFormat*>(dateFormat);

    if (simDateFormat != nullptr) {

        simDateFormat->toPattern(pattern);

    }

    dateIntvFormat = DateIntervalFormat::createInstance(pattern, locale, status);

}



void DateTimeFormat::FixPatternPartOne()

{

    if (hour12 == "true") {

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("H")),

            icu::UnicodeString::fromUTF8(StringPiece("h")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),

            icu::UnicodeString::fromUTF8(StringPiece("h")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),

            icu::UnicodeString::fromUTF8(StringPiece("h")));

    } else if (hour12 == "false") {

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("h")),

            icu::UnicodeString::fromUTF8(StringPiece("H")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),

            icu::UnicodeString::fromUTF8(StringPiece("H")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),

            icu::UnicodeString::fromUTF8(StringPiece("H")));

        RemoveAmPmChar();

    } else if (hourCycle != "") {

        FixPatternPartTwo();

    }

}



void DateTimeFormat::FixPatternPartTwo()

{

    if (hourCycle == "h11") {

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("h")),

            icu::UnicodeString::fromUTF8(StringPiece("k")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("H")),

            icu::UnicodeString::fromUTF8(StringPiece("k")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),

            icu::UnicodeString::fromUTF8(StringPiece("k")));

    } else if (hourCycle == "h12") {

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("H")),

            icu::UnicodeString::fromUTF8(StringPiece("h")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),

            icu::UnicodeString::fromUTF8(StringPiece("h")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),

            icu::UnicodeString::fromUTF8(StringPiece("h")));

    } else if (hourCycle == "h23") {

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("h")),

            icu::UnicodeString::fromUTF8(StringPiece("K")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("H")),

            icu::UnicodeString::fromUTF8(StringPiece("K")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),

            icu::UnicodeString::fromUTF8(StringPiece("K")));

        RemoveAmPmChar();

    } else if (hourCycle == "h24") {

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("h")),

            icu::UnicodeString::fromUTF8(StringPiece("H")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("k")),

            icu::UnicodeString::fromUTF8(StringPiece("H")));

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("K")),

            icu::UnicodeString::fromUTF8(StringPiece("H")));

        RemoveAmPmChar();

    }

}



void DateTimeFormat::RemoveAmPmChar()

{

    std::string patternString = "";

    pattern.toUTF8String(patternString);

    size_t amPmCharStartIdx = 0;

    size_t amPmCharEndIdx = 0;

    for (size_t i = 0; i < patternString.length(); i++) {

        if (patternString[i] != 'a') {

            continue;

        }

        if ((i + 1) < patternString.length() && patternString[i + 1] == 't') {

            continue;

        }

        if (!i) {

            amPmCharStartIdx = i;

        } else {

            amPmCharStartIdx = i - 1;

            while (amPmCharStartIdx > 0 && patternString[amPmCharStartIdx] == ' ') {

                amPmCharStartIdx -= 1;

            }

            if (amPmCharStartIdx || patternString[amPmCharStartIdx] != ' ') {

                amPmCharStartIdx += 1;

            }

        }

        amPmCharEndIdx = i + 1;

        while (amPmCharEndIdx < patternString.length() && patternString[amPmCharEndIdx] == ' ') {

            amPmCharEndIdx += 1;

        }

        break;

    }

    size_t length = amPmCharEndIdx - amPmCharStartIdx;

    if (length) {

        if (!amPmCharStartIdx || amPmCharEndIdx == patternString.length()) {

            patternString = patternString.replace(amPmCharStartIdx, length, "");

        } else {

            patternString = patternString.replace(amPmCharStartIdx, length, " ");

        }

        pattern = icu::UnicodeString(patternString.data(), patternString.length());

    }

}



void DateTimeFormat::InitDateFormat(UErrorCode &status)

{

    if (!dateStyle.empty() || !timeStyle.empty()) {

        DateFormat::EStyle dateStyleValue = DateFormat::EStyle::kNone;

        DateFormat::EStyle timeStyleValue = DateFormat::EStyle::kNone;

        if (!dateStyle.empty()) {

            if (dateTimeStyle.count(dateStyle) > 0) {

                dateStyleValue = dateTimeStyle[dateStyle];

            } else if (dateStyle == "auto") {

                dateStyleValue = DefaultDTStyle[defaultStyle];

            }

        }

        if (!timeStyle.empty()) {

            if (dateTimeStyle.count(timeStyle) > 0) {

                timeStyleValue = dateTimeStyle[timeStyle];

            } else if (timeStyle == "auto") {

                timeStyleValue = DefaultDTStyle[defaultStyle];

            }

        }

        dateFormat = DateFormat::createDateTimeInstance(dateStyleValue, timeStyleValue, locale);

        SimpleDateFormat *simDateFormat = static_cast<SimpleDateFormat*>(dateFormat);

        if (simDateFormat != nullptr) {

            simDateFormat->toPattern(pattern);

        }

        FixPatternPartOne();

        delete dateFormat;

        dateFormat = new SimpleDateFormat(pattern, locale, status);

        if (!U_SUCCESS(status)) {

            return;

        }

    } else {

        auto patternGenerator =

            std::unique_ptr<DateTimePatternGenerator>(DateTimePatternGenerator::createInstance(locale, status));

        if (!U_SUCCESS(status)) {

            return;

        }

        ComputePattern();

        pattern =

            patternGenerator->replaceFieldTypes(patternGenerator->getBestPattern(pattern, status), pattern, status);

        pattern = patternGenerator->getBestPattern(pattern, status);

        SetDayPeriod();

        status = U_ZERO_ERROR;

        dateFormat = new SimpleDateFormat(pattern, locale, status);

        if (!U_SUCCESS(status)) {

            return;

        }

    }

    status = U_ZERO_ERROR;

    dateIntvFormat = DateIntervalFormat::createInstance(pattern, locale, status);

}



void DateTimeFormat::SetDayPeriod()

{

    if (dayPeriod == "short" || (dayPeriod == "auto" && defaultStyle ==  DefaultStyle::DEFAULT)) {

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("a")),

            icu::UnicodeString::fromUTF8(StringPiece("B")));

    } else if (dayPeriod == "long" || (dayPeriod == "auto" && defaultStyle ==  DefaultStyle::LONG)) {

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("a")),

            icu::UnicodeString::fromUTF8(StringPiece("BBBB")));

    } else if (dayPeriod == "narrow" || (dayPeriod == "auto" && defaultStyle ==  DefaultStyle::SHORT)) {

        pattern.findAndReplace(icu::UnicodeString::fromUTF8(StringPiece("a")),

            icu::UnicodeString::fromUTF8(StringPiece("BBBBB")));

    }

}



void DateTimeFormat::ParseConfigsPartOne(std::map<std::string, std::string> &configs)

{

    if (configs.count("dateStyle") > 0) {

        dateStyle = configs["dateStyle"];

    }

    if (configs.count("timeStyle") > 0) {

        timeStyle = configs["timeStyle"];

    }

    if (configs.count("year") > 0) {

        year = configs["year"];

    }

    if (configs.count("month") > 0) {

        month = configs["month"];

    }

    if (configs.count("day") > 0) {

        day = configs["day"];

    }

    if (configs.count("hour") > 0) {

        hour = configs["hour"];

    }

    if (configs.count("minute") > 0) {

        minute = configs["minute"];

    }

    if (configs.count("second") > 0) {

        second = configs["second"];

    }

}



void DateTimeFormat::ParseConfigsPartTwo(std::map<std::string, std::string> &configs)

{

    if (configs.count("hourCycle") > 0) {

        hourCycle = configs["hourCycle"];

    }

    if (configs.count("timeZone") > 0) {

        timeZone = configs["timeZone"];

    }

    if (configs.count("numberingSystem") > 0) {

        numberingSystem = configs["numberingSystem"];

    }

    if (configs.count("hour12") > 0) {

        hour12 = configs["hour12"];

    }

    if (configs.count("weekday") > 0) {

        weekday = configs["weekday"];

    }

    if (configs.count("era") > 0) {

        era = configs["era"];

    }

    if (configs.count("timeZoneName") > 0) {

        timeZoneName = configs["timeZoneName"];

    }

    if (configs.count("dayPeriod") > 0) {

        dayPeriod = configs["dayPeriod"];

    }

    if (configs.count("localeMatcher") > 0) {

        localeMatcher = configs["localeMatcher"];

    }

    if (configs.count("formatMatcher") > 0) {

        formatMatcher = configs["formatMatcher"];

    }

}



void DateTimeFormat::ComputeSkeleton()

{

    if (year.empty() && month.empty() && day.empty() && hour.empty() && minute.empty() && second.empty() &&

        weekday.empty()) {

        pattern.append("yMd");

    }

    AddOptions(year, yearChar);

    AddOptions(month, monthChar);

    AddOptions(day, dayChar);

    AddOptions(hour, hourChar);

    AddOptions(minute, minuteChar);

    AddOptions(second, secondChar);

    if ((hourCycle == "h12" || hourCycle == "h11" || hour12 == "true") && !hour.empty()) {

        pattern.append(amPmChar);

    }

    AddOptions(timeZoneName, timeZoneChar);

    AddOptions(weekday, weekdayChar);

    AddOptions(era, eraChar);

}



void DateTimeFormat::AddOptions(std::string option, char16_t optionChar)

{

    if (!option.empty()) {

        pattern.append(optionChar);

    }

}



void DateTimeFormat::ComputeHourCycleChars()

{

    if (!hour12.empty()) {

        if (hour12 == "true") {

            hourNumericString = "h";

            hourTwoDigitString = "hh";

        } else {

            hourNumericString = "H";

            hourTwoDigitString = "HH";

        }

    } else {

        if (hourCycle == "h11") {

            hourNumericString = "K";

            hourTwoDigitString = "KK";

        } else if (hourCycle == "h12") {

            hourNumericString = "h";

            hourTwoDigitString = "hh";

        } else if (hourCycle == "h23") {

            hourNumericString = "H";

            hourTwoDigitString = "HH";

        } else if (hourCycle == "h24") {

            hourNumericString = "k";

            hourTwoDigitString = "kk";

        }

    }

}



void DateTimeFormat::ComputePattern()

{

    ComputePartOfPattern(year, yearChar, "yy", "yyyy");

    ComputePartOfPattern(day, dayChar, "dd", "d");

    ComputePartOfPattern(hour, hourChar, hourTwoDigitString, hourNumericString);

    ComputePartOfPattern(minute, minuteChar, "mm", "mm");

    ComputePartOfPattern(second, secondChar, "ss", "ss");

    if (!month.empty()) {

        UnicodeString monthOfPattern = UnicodeString(monthChar);

        int32_t length = monthOfPattern.length();

        if (month == "numeric" && length != NUMERIC_LENGTH) {

            pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("M")));

        } else if (month == "2-digit" && length != TWO_DIGIT_LENGTH) {

            pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("MM")));

        } else if ((month == "long" && length != LONG_LENGTH) || (month == "auto" &&

            defaultStyle ==  DefaultStyle::LONG)) {

            pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("MMMM")));

        } else if ((month == "short" && length != SHORT_LENGTH) || (month == "auto" &&

            (defaultStyle ==  DefaultStyle::DEFAULT || defaultStyle ==  DefaultStyle::SHORT))) {

            pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("MMM")));

        } else if (month == "narrow" && length != NARROW_LENGTH) {

            pattern.findAndReplace(monthOfPattern, UnicodeString::fromUTF8(StringPiece("MMMMM")));

        }

    }



    ComputeTimeZoneOfPattern(timeZoneName, timeZoneChar, "zzzz", "O");

    ComputeWeekdayOfPattern(weekday, weekdayChar, "EEEE", "E", "EEEEE");

    ComputeEraOfPattern(era, eraChar, "GGGG", "G", "GGGGG");

}



void DateTimeFormat::ComputePartOfPattern(std::string option, char16_t character, std::string twoDigitChar,

    std::string numericChar)

{

    if (!option.empty()) {

        UnicodeString curPartOfPattern = UnicodeString(character);

        if (option == "2-digit") {

            pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(twoDigitChar)));

        } else if (option == "numeric") {

            pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(numericChar)));

        }

    }

}



void DateTimeFormat::ComputeTimeZoneOfPattern(std::string option, char16_t character, std::string longChar,

    std::string shortChar)

{

    if (!option.empty()) {

        UnicodeString timeZoneOfPattern = UnicodeString(character);

        if (option == "long" || (option == "auto" && defaultStyle ==  DefaultStyle::LONG)) {

            pattern.findAndReplace(timeZoneOfPattern, UnicodeString::fromUTF8(StringPiece(longChar)));

        } else if (option == "short" || (option == "auto" && (defaultStyle ==  DefaultStyle::DEFAULT ||

            defaultStyle ==  DefaultStyle::SHORT))) {

            pattern.findAndReplace(timeZoneOfPattern, UnicodeString::fromUTF8(StringPiece(shortChar)));

        }

    }

}



void DateTimeFormat::ComputeWeekdayOfPattern(std::string option, char16_t character, std::string longChar,

    std::string shortChar, std::string narrowChar)

{

    if (!option.empty()) {

        UnicodeString curPartOfPattern = UnicodeString(character);

        int32_t length = curPartOfPattern.length();

        if ((option == "long" && length != LONG_ERA_LENGTH) || (option == "auto" &&

            defaultStyle ==  DefaultStyle::LONG)) {

            pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(longChar)));

        } else if ((option == "short" && length != SHORT_ERA_LENGTH) || (option == "auto" &&

            (defaultStyle ==  DefaultStyle::DEFAULT || defaultStyle ==  DefaultStyle::SHORT))) {

            pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(shortChar)));

        } else if (option == "narrow" && length != NARROW_LENGTH) {

            pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(narrowChar)));

        }

    }

}



void DateTimeFormat::ComputeEraOfPattern(std::string option, char16_t character, std::string longChar,

    std::string shortChar, std::string narrowChar)

{

    if (!option.empty()) {

        UnicodeString curPartOfPattern = UnicodeString(character);

        int32_t length = curPartOfPattern.length();

        if ((option == "long" && length != LONG_ERA_LENGTH) || (option == "auto" &&

            defaultStyle ==  DefaultStyle::LONG)) {

            pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(longChar)));

        } else if ((option == "short" && length != SHORT_ERA_LENGTH) || (option == "auto" &&

            defaultStyle ==  DefaultStyle::DEFAULT)) {

            pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(shortChar)));

        } else if ((option == "narrow" && length != NARROW_LENGTH) || (option == "auto" &&

            defaultStyle ==  DefaultStyle::SHORT)) {

            pattern.findAndReplace(curPartOfPattern, UnicodeString::fromUTF8(StringPiece(narrowChar)));

        }

    }

}



int64_t DateTimeFormat::GetArrayValue(int64_t *dateArray, size_t index, size_t size)

{

    if (index < size) {

        return dateArray[index];

    } else {

        return 0;

    }

}



std::string DateTimeFormat::GetSystemTimezone()

{

    std::string systemTimezone = LocaleConfig::GetSystemTimezone();

    if (systemTimezone.length() == 0) {

        systemTimezone = DEFAULT_TIMEZONE;

    }

    return systemTimezone;

}



std::string DateTimeFormat::Format(int64_t milliseconds)

{

    if (!createSuccess) {

        return "";

    }

    UErrorCode status = U_ZERO_ERROR;

    std::string result;

    UnicodeString dateString;

    calendar->clear();

    std::string timezoneStr = timeZone.empty() ? GetSystemTimezone() : timeZone;

    auto zone = std::unique_ptr<TimeZone>(TimeZone::createTimeZone(timezoneStr.c_str()));

    calendar->setTimeZone(*zone);

    dateFormat->setTimeZone(*zone);

    calendar->setTime((UDate)milliseconds, status);

    dateFormat->format(calendar->getTime(status), dateString, status);

    dateString.toUTF8String(result);

    return result;

}



std::string DateTimeFormat::FormatRange(int64_t fromMilliseconds, int64_t toMilliseconds)

{

    if (!createSuccess) {

        return "";

    }

    UErrorCode status = U_ZERO_ERROR;

    std::string result;

    UnicodeString dateString;

    calendar->clear();

    std::string timezoneStr = timeZone.empty() ? GetSystemTimezone() : timeZone;

    auto zone = std::unique_ptr<TimeZone>(TimeZone::createTimeZone(timezoneStr.c_str()));

    calendar->setTimeZone(*zone);

    dateIntvFormat->setTimeZone(*zone);

    calendar->setTime((UDate)fromMilliseconds, status);



    auto toCalendar = std::unique_ptr<Calendar>(Calendar::createInstance(locale, status));

    if (status != U_ZERO_ERROR || toCalendar == nullptr) {

        return "";

    }

    toCalendar->clear();

    toCalendar->setTimeZone(*zone);

    toCalendar->setTime((UDate)toMilliseconds, status);

    FieldPosition pos = 0;

    dateIntvFormat->format(*calendar, *toCalendar, dateString, pos, status);

    dateString.toUTF8String(result);

    return result;

}



void DateTimeFormat::GetResolvedOptions(std::map<std::string, std::string> &map)

{

    map.insert(std::make_pair("locale", localeTag));

    if (!(localeInfo->GetCalendar()).empty()) {

        map.insert(std::make_pair("calendar", localeInfo->GetCalendar()));

    } else {

        map.insert(std::make_pair("calendar", calendar->getType()));

    }

    if (!dateStyle.empty()) {

        map.insert(std::make_pair("dateStyle", dateStyle));

    }

    if (!timeStyle.empty()) {

        map.insert(std::make_pair("timeStyle", timeStyle));

    }

    if (!hourCycle.empty()) {

        map.insert(std::make_pair("hourCycle", hourCycle));

    } else if (!(localeInfo->GetHourCycle()).empty()) {

        map.insert(std::make_pair("hourCycle", localeInfo->GetHourCycle()));

    }

    if (!timeZone.empty()) {

        map.insert(std::make_pair("timeZone", timeZone));

    } else {

        UnicodeString timeZoneID("");

        std::string timeZoneString;

        dateFormat->getTimeZone().getID(timeZoneID).toUTF8String(timeZoneString);

        map.insert(std::make_pair("timeZone", timeZoneString));

    }

    if (!timeZoneName.empty()) {

        map.insert(std::make_pair("timeZoneName", timeZoneName));

    }

    if (!numberingSystem.empty()) {

        map.insert(std::make_pair("numberingSystem", numberingSystem));

    } else if (!(localeInfo->GetNumberingSystem()).empty()) {

        map.insert(std::make_pair("numberingSystem", localeInfo->GetNumberingSystem()));

    } else {

        UErrorCode status = U_ZERO_ERROR;

        auto numSys = std::unique_ptr<NumberingSystem>(NumberingSystem::createInstance(locale, status));

        if (status != U_ZERO_ERROR) {

            map.insert(std::make_pair("numberingSystem", numSys->getName()));

        }

    }

    GetAdditionalResolvedOptions(map);

}



void DateTimeFormat::GetAdditionalResolvedOptions(std::map<std::string, std::string> &map)

{

    if (!hour12.empty()) {

        map.insert(std::make_pair("hour12", hour12));

    }

    if (!weekday.empty()) {

        map.insert(std::make_pair("weekday", weekday));

    }

    if (!era.empty()) {

        map.insert(std::make_pair("era", era));

    }

    if (!year.empty()) {

        map.insert(std::make_pair("year", year));

    }

    if (!month.empty()) {

        map.insert(std::make_pair("month", month));

    }

    if (!day.empty()) {

        map.insert(std::make_pair("day", day));

    }

    if (!hour.empty()) {

        map.insert(std::make_pair("hour", hour));

    }

    if (!minute.empty()) {

        map.insert(std::make_pair("minute", minute));

    }

    if (!second.empty()) {

        map.insert(std::make_pair("second", second));

    }

    if (!dayPeriod.empty()) {

        map.insert(std::make_pair("dayPeriod", dayPeriod));

    }

    if (!localeMatcher.empty()) {

        map.insert(std::make_pair("localeMatcher", localeMatcher));

    }

    if (!formatMatcher.empty()) {

        map.insert(std::make_pair("formatMatcher", formatMatcher));

    }

}



std::string DateTimeFormat::GetDateStyle() const

{

    return dateStyle;

}



std::string DateTimeFormat::GetTimeStyle() const

{

    return timeStyle;

}



std::string DateTimeFormat::GetHourCycle() const

{

    return hourCycle;

}



std::string DateTimeFormat::GetTimeZone() const

{

    return timeZone;

}



std::string DateTimeFormat::GetTimeZoneName() const

{

    return timeZoneName;

}



std::string DateTimeFormat::GetNumberingSystem() const

{

    return numberingSystem;

}



std::string DateTimeFormat::GetHour12() const

{

    return hour12;

}



std::string DateTimeFormat::GetWeekday() const

{

    return weekday;

}



std::string DateTimeFormat::GetEra() const

{

    return era;

}



std::string DateTimeFormat::GetYear() const

{

    return year;

}



std::string DateTimeFormat::GetMonth() const

{

    return month;

}



std::string DateTimeFormat::GetDay() const

{

    return day;

}



std::string DateTimeFormat::GetHour() const

{

    return hour;

}



std::string DateTimeFormat::GetMinute() const

{

    return minute;

}



std::string DateTimeFormat::GetSecond() const

{

    return second;

}



bool DateTimeFormat::Init()

{

    return true;

}



DefaultStyle DateTimeFormat::GetDefaultStyle()

{

    auto defaultStyle = DefaultStyle::DEFAULT;

    auto plugin = Plugin::INTL::Create();

    if (!plugin) {

        return defaultStyle;

    } else {

        std::string deviceType = plugin->GetDeviceType();

        if (DeviceToStyle.find(deviceType) != DeviceToStyle.end()) {

            defaultStyle = DeviceToStyle[deviceType];

        }

    }

    return defaultStyle;

}

} // namespace I18n

} // namespace Global

} // namespace OHOS