Thai date and time string formatter
    Formatting directives similar to datetime.strftime()

    Will use Thai names and Thai Buddhist Era for these directives:
    - %a abbreviated weekday name
    - %A full weekday name
    - %b abbreviated month name
    - %B full month name
    - %y year without century
    - %Y year with century
    - %c date and time representation
    - %v short date representation (undocumented)

    Other directives will be passed to datetime.strftime()

    Note 1:
    The Thai Buddhist Era (BE) year is simply converted from AD by adding 543.
    This is certainly not accurate for years before 1941 AD,
    due to the change in Thai New Year's Day.

    Note 2:
    This meant to be an interrim solution, since Python standard's locale module
    (which relied on C's strftime()) does not support "th" or "th_TH" locale yet.
    If supported, we can just locale.setlocale(locale.LC_TIME, "th_TH") and
    then use native datetime.strftime().

    Note 3:
    We trying to make this platform-independent and support extentions as many as possible,
    See these links for strftime() extensions in POSIX, BSD, and GNU libc:
    - Python https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
    - C http://www.cplusplus.com/reference/ctime/strftime/
    - GNU https://metacpan.org/pod/POSIX::strftime::GNU
    - Linux https://linux.die.net/man/3/strftime
    - OpenBSD https://man.openbsd.org/strftime.3
    - FreeBSD https://www.unix.com/man-page/FreeBSD/3/strftime/
    - macOS https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/strftime.3.html
    - PHP https://secure.php.net/manual/en/function.strftime.php
    - JavaScript's implementation https://github.com/samsonjs/strftime
    - strftime() quick reference http://www.strftime.net/

    :return: Date and time spelled out in text, with month in Thai name and year in Thai Buddhist era. The year is simply converted from AD by adding 543 (will not accurate for years before 1941 AD, due to change in Thai New Year's Day).

def thai_strftime(
    datetime: datetime.datetime, fmt: str, thaidigit: bool = False
) -> str:
    """
    Thai date and time string formatter
    Formatting directives similar to datetime.strftime()

    Will use Thai names and Thai Buddhist Era for these directives:
    - %a abbreviated weekday name
    - %A full weekday name
    - %b abbreviated month name
    - %B full month name
    - %y year without century
    - %Y year with century
    - %c date and time representation
    - %v short date representation (undocumented)

    Other directives will be passed to datetime.strftime()

    Note 1:
    The Thai Buddhist Era (BE) year is simply converted from AD by adding 543.
    This is certainly not accurate for years before 1941 AD,
    due to the change in Thai New Year's Day.

    Note 2:
    This meant to be an interrim solution, since Python standard's locale module
    (which relied on C's strftime()) does not support "th" or "th_TH" locale yet.
    If supported, we can just locale.setlocale(locale.LC_TIME, "th_TH") and
    then use native datetime.strftime().

    Note 3:
    We trying to make this platform-independent and support extentions as many as possible,
    See these links for strftime() extensions in POSIX, BSD, and GNU libc:
    - Python https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
    - C http://www.cplusplus.com/reference/ctime/strftime/
    - GNU https://metacpan.org/pod/POSIX::strftime::GNU
    - Linux https://linux.die.net/man/3/strftime
    - OpenBSD https://man.openbsd.org/strftime.3
    - FreeBSD https://www.unix.com/man-page/FreeBSD/3/strftime/
    - macOS https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/strftime.3.html
    - PHP https://secure.php.net/manual/en/function.strftime.php
    - JavaScript's implementation https://github.com/samsonjs/strftime
    - strftime() quick reference http://www.strftime.net/

    :return: Date and time spelled out in text, with month in Thai name and year in Thai Buddhist era. The year is simply converted from AD by adding 543 (will not accurate for years before 1941 AD, due to change in Thai New Year's Day).
    """
    thaidate_parts = []

    i = 0
    fmt_len = len(fmt)
    while i < fmt_len:
        str_ = ""
        if fmt[i] == "%":
            j = i + 1
            if j < fmt_len:
                fmt_char = fmt[j]
                if fmt_char in _NEED_L10N:  # requires localization?
                    str_ = _thai_strftime(datetime, fmt_char)
                elif fmt_char in _EXTENSIONS:

                    if fmt_char == "-":
                        # GNU libc extension, no padding
                        k = j + 1
                        if k < fmt_len:
                            fmt_char_nopad = fmt[k]
                            if (
                                fmt_char_nopad in _NEED_L10N
                            ):  # check if requires localization
                                str_ = _thai_strftime(datetime, fmt_char_nopad)
                            else:
                                str_ = datetime.strftime(f"%-{fmt_char_nopad}")
                            i = i + 1  # consume char after "-"
                        else:
                            str_ = "-"  # "-" at the end of string has no meaning
                    elif fmt_char == "_":
                        # GNU libc extension, explicitly specify space (" ") for padding
                        # Not implemented yet
                        pass
                    elif fmt_char == "0":
                        # GNU libc extension, explicitly specify zero ("0") for padding
                        # Not implemented yet
                        pass
                    elif fmt_char == "E":
                        # POSIX extension, uses the locale's alternative representation
                        # Not implemented yet
                        pass
                    elif fmt_char == "O":
                        # POSIX extension, uses the locale's alternative numeric symbols
                        # Not implemented yet
                        pass

                elif fmt_char:
                    # the rest of directives, just pass to Python's standard strftime()
                    str_ = datetime.strftime(f"%{fmt_char}")

                i = i + 1  # consume char after "%"
            else:
                str_ = "%"
        else:
            str_ = fmt[i]

        thaidate_parts.append(str_)
        i = i + 1

    thaidate_text = "".join(thaidate_parts)

    if thaidigit:
        thaidate_text = thaidate_text.translate(_HA_TH_DIGITS)

    return thaidate_text