thai_buddhist_date
Screenshots & Demo
ðŽ Click to view video demo
A tiny Dart library for working with Thai Buddhist Era dates (āļ.āļĻ.), with selectable output era (āļ.āļĻ./āļ.āļĻ.), safe tokenâaware formatting, flexible parsing, and optional Flutter widgets.
Looking for calendar and dialog pickers? See the companion UI package:
- thai_buddhist_date_pickers â https://pub.flutter-io.cn/packages/thai_buddhist_date_pickers
Highlights
- Format with BE or CE:
format(DateTime, era: ...)outputs the year in āļ.āļĻ. (BE) or āļ.āļĻ. (CE). - Parse both BE and CE seamlessly:
parse(String)detects BE years (>= 2400) and normalizes to a CEDateTimeinternally. - Tokenâaware formatter: Only the year tokens are replaced when outputting BE, so patterns like
yyyy-MM-ddorMMMM yyyyremain safe. - Clean Architecture service: Highâlevel
ThaiDateServicewith caching and sync formatting for numeric patterns. - Flutter extras (optional): A lightweight month calendar and a set of date pickers (single, dateâtime with preview, range, multiâdate, and fullscreen) with theming hooks.
Install
Add to your pubspec.yaml:
dependencies:
thai_buddhist_date: ^0.2.7
Then run dart pub get or flutter pub get.
Quick start
import 'package:thai_buddhist_date/thai_buddhist_date.dart';
void main() {
// Parse either BE or CE and get a DateTime (internally CE)
final dt = parse('2568-08-22'); // BE input -> CE internally (2025-08-22)
// Top-level format is synchronous
print(format(dt, pattern: 'yyyy-MM-dd', era: Era.ce)); // 2025-08-22
}
Locale initialization for Flutter
If you need localized month/weekday names (e.g., MMMM yyyy), initialize the Thai locale before building the UI:
import 'package:flutter/material.dart';
import 'package:thai_buddhist_date/thai_buddhist_date.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Load date symbols for Thai before using patterns like 'MMMM' or 'EEE'
await ThaiDateService().initializeLocale('th_TH');
runApp(const MyApp());
}
Service cheatsheet (Clean Architecture)
final service = ThaiDateService();
// Format
final be = await service.format(ThaiDate.fromDateTime(DateTime(2025, 8, 22)), pattern: 'fullText');
final iso = service.formatSync(ThaiDate.fromDateTime(DateTime(2025, 8, 22)), pattern: 'iso');
// Parse (accepts BE or CE) â returns ThaiDate (BE year)
final t = service.parse('2568-08-22', pattern: 'yyyy-MM-dd');
// Now helper
final label = await service.formatNow(pattern: 'fullText');
// Global config
service.setEra(Era.be);
service.setLanguage(ThaiLanguage.thai); // sets locale to 'th_TH'
await service.initializeLocale('th_TH');
Multi-language date/time/date&time
- Pick any locale via the
locale:parameter or set language globally on the service. - Use the same API for date (yyyy-MM-dd), time (HH:mm), or combined (dd/MM/yyyy HH:mm).
final svc = ThaiDateService();
// Date only
final frDate = await svc.formatNow(pattern: 'yyyy-MM-dd', locale: 'fr');
// Time only
final frTime = await svc.formatNow(pattern: 'HH:mm', locale: 'fr');
// Date & Time
final frDateTime = await svc.formatNow(pattern: 'dd/MM/yyyy HH:mm', locale: 'fr');
// Override per call with another language
final esFull = await svc.formatNow(pattern: 'fullText', locale: 'es');
Thai full date format (āļ§āļąāļ āđāļāļ·āļāļ āļāļĩ)
Using a preset pattern, with BE or CE:
final d = DateTime(2025, 8, 25);
print(format(d, pattern: 'dmy', era: Era.be)); // 25 āļŠāļīāļāļŦāļēāļāļĄ 2568
print(format(d, pattern: 'dmy', era: Era.ce)); // 25 āļŠāļīāļāļŦāļēāļāļĄ 2025
Custom patterns
Use any intl-style pattern: yyyy-MM-dd, dd/MM/yyyy, HH:mm, d MMMM yyyy, etc.
final d = DateTime(2025, 8, 25);
print(format(d, pattern: 'dd/MM/yyyy')); // 25/08/2568 (BE)
print(format(d, pattern: 'MMMM yyyy')); // āļŠāļīāļāļŦāļēāļāļĄ 2568 (BE)
print(format(d, pattern: 'MMMM yyyy', era: Era.ce)); // āļŠāļīāļāļŦāļēāļāļĄ 2025 (CE)
Creative parse/format helpers (BE/CE, all common formats)
You can use parseThaiDate and formatThaiDate for flexible, ergonomic conversion between String and DateTime, supporting BE/CE and many formats:
// Parsing (String to DateTime)
parseThaiDate('03092568'); // BE, compact
parseThaiDate('03-09-2568'); // BE, dash
parseThaiDate('03/09/2568'); // BE, slash
parseThaiDate('03.09.2568'); // BE, dot
parseThaiDate('2568-09-03'); // BE, ISO
parseThaiDate('2568.09.03'); // BE, ISO dot
parseThaiDate('2568/09/03'); // BE, ISO slash
parseThaiDate('3/9/2568'); // BE, single-digit
parseThaiDate('3-9-2568'); // BE, single-digit dash
parseThaiDate('3.9.2568'); // BE, single-digit dot
// Parsing CE
parseThaiDate('03092025', era: Era.ce); // CE, compact
parseThaiDate('03-09-2025', era: Era.ce); // CE, dash
parseThaiDate('03/09/2025', era: Era.ce); // CE, slash
parseThaiDate('03.09.2025', era: Era.ce); // CE, dot
parseThaiDate('2025-09-03', era: Era.ce); // CE, ISO
parseThaiDate('2025.09.03', era: Era.ce); // CE, ISO dot
parseThaiDate('2025/09/03', era: Era.ce); // CE, ISO slash
parseThaiDate('3/9/2025', era: Era.ce); // CE, single-digit
parseThaiDate('3-9-2025', era: Era.ce); // CE, single-digit dash
parseThaiDate('3.9.2025', era: Era.ce); // CE, single-digit dot
// Formatting (DateTime to String)
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'dd/MM/yyyy'); // '03/09/2568'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'dd/MM/yyyy'); // '03/09/2025'
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'dd-MM-yyyy'); // '03-09-2568'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'dd-MM-yyyy'); // '03-09-2025'
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'dd.MM.yyyy'); // '03.09.2568'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'dd.MM.yyyy'); // '03.09.2025'
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'yyyy-MM-dd'); // '2568-09-03'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'yyyy-MM-dd'); // '2025-09-03'
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'yyyy.MM.dd'); // '2568.09.03'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'yyyy.MM.dd'); // '2025.09.03'
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'yyyy/MM/dd'); // '2568/09/03'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'yyyy/MM/dd'); // '2025/09/03'
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'd/M/yyyy'); // '3/9/2568'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'd/M/yyyy'); // '3/9/2025'
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'd-M-yyyy'); // '3-9-2568'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'd-M-yyyy'); // '3-9-2025'
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'd.M.yyyy'); // '3.9.2568'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'd.M.yyyy'); // '3.9.2025'
// Custom formats
formatThaiDate(DateTime(2568,9,3), era: Era.be, format: 'ddMMyyyy'); // '03092568'
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'ddMMyyyy'); // '03092025'
// Extensible: add your own formats
final customFormats = {'myCustom': 'yyyyMMdd'};
parseThaiDate('20250903', format: 'yyyyMMdd', era: Era.ce, customFormats: customFormats);
formatThaiDate(DateTime(2025,9,3), era: Era.ce, format: 'yyyyMMdd'); // '20250903'
Explicit-era parsing for BE inputs
When your input is known to be āļ.āļĻ., parse with an explicit era:
final parsed = ThaiDateService().parseWithEra(
'25 āļŠāļīāļāļŦāļēāļāļĄ 2568',
era: Era.be,
pattern: 'd MMMM yyyy',
);
print(parsed?.toDateTime()); // 2025-08-25 00:00:00.000
Common recipes
// 1) Today in BE and CE (compat functions)
print(formatNow(pattern: 'dd/MM/yyyy', era: Era.be));
print(formatNow(pattern: 'dd/MM/yyyy', era: Era.ce));
// 2) Localized full text (ensure locale first)
await ThaiDateService().initializeLocale('th_TH');
print(formatNow(pattern: 'fullText'));
print(formatNow(pattern: 'fullText', locale: 'en_US'));
// 3) Extensions
print(DateTime(2025, 8, 22).toThaiStringSync(pattern: 'yyyy-MM-dd'));
// 4) Parsing
print(parse('22/08/2568', format: 'dd/MM/yyyy'));
print(parse('2025-08-22', format: 'yyyy-MM-dd'));
Example: Thai date picker (output āļ.āļĻ. āļ āļēāļĐāļēāđāļāļĒ)
import 'package:flutter/material.dart';
import 'package:thai_buddhist_date_pickers/thai_buddhist_date_pickers.dart';
import 'package:thai_buddhist_date/thai_buddhist_date.dart' as tbd;
// ... inside a widget method
final picked = await showThaiDatePicker(
context,
locale: 'th_TH',
);
if (picked != null) {
final label = tbd.format(picked, pattern: 'dmy', era: tbd.Era.be);
print(label); // āđāļāđāļ 27 āļŠāļīāļāļŦāļēāļāļĄ 2568
}
Ergonomics
- Global settings:
final svc = ThaiDateService();
svc.setEra(Era.be);
svc.setLanguage(ThaiLanguage.thai);
- Quick language switch:
// Use `setLanguage` or pass `locale:` per call
- Reusable formatter:
// Reusable: hold a service instance and reuse it
- Extensions:
// DateTime -> String
final s = await DateTime(2025, 8, 22).toThaiString(pattern: 'yyyy-MM-dd', era: Era.ce);
Backward compatibility and sync vs async
- Top-level helpers
format(...)andformatNow(...)are synchronous (String). Theyâre drop-in replacements for legacy usage and safe to call withoutawait. - The high-level
ThaiDateServiceexposes bothformat(...)(async) andformatSync(...)(sync for numeric-only patterns). Use the service if you need explicit control, caching, and advanced parse/convert helpers. - Legacy shims like
ThaiCalendar,ThaiDateSettings,ThaiFormatter, andTbdLocalesremain available for existing code; they map to the new internals. - If you output localized month/weekday names (e.g.,
MMMM,EEE), callawait ThaiDateService().initializeLocale('th_TH')once at startup.
Flutter widgets (optional)
This package ships a simple calendar and multiple pickers. Theyâre intentionally lightweight so you can customize them freely.
Month calendar
BuddhistGregorianCalendar renders a singleâmonth grid that formats the header with BE or CE.
BuddhistGregorianCalendar(
era: Era.be, // or Era.ce
dayBuilder: customDay?, // optional: build your own day cells
)
Pickers
- Single date dialog:
showThaiDatePicker(...) - Dateâtime dialog with live preview and
formatString:showThaiDateTimePicker(...) - Convenience wrappers that return formatted strings:
showThaiDatePickerFormatted(...),showThaiDateTimePickerFormatted(...) - Range selection dialog:
showThaiDateRangePicker(...) - Multiâdate selection dialog:
showThaiMultiDatePicker(...) - Fullscreen variant (single):
showThaiDatePickerFullscreen(...)
All dialogs support theming/spacing parameters: shape, titlePadding, contentPadding, actionsPadding, insetPadding.
Basic usage:
// Single date
final picked = await showThaiDatePicker(
context,
locale: 'th_TH',
);
// Date-time with preview (custom preview format)
final dt = await showThaiDateTimePicker(
context,
formatString: 'dd/MM/yyyy HH:mm',
);
// Range (dialog)
final range = await showThaiDateRangePicker(context, era: Era.be, locale: 'th_TH');
// Multi-date
final multiple = await showThaiMultiDatePicker(context, era: Era.be, locale: 'th_TH');
API cheatsheet:
Future<DateTime?> showThaiDatePicker(...)
Future<DateTime?> showThaiDateTimePicker(..., { String formatString = 'dd/MM/yyyy HH:mm' })
Future<String?> showThaiDatePickerFormatted(..., { String formatString = 'dd/MM/yyyy' })
Future<String?> showThaiDateTimePickerFormatted(..., { String formatString = 'dd/MM/yyyy HH:mm' })
Future<DateTimeRange?> showThaiDateRangePicker(...)
Future<Set<DateTime>?> showThaiMultiDatePicker(...)
Future<DateTime?> showThaiDatePickerFullscreen(...)
Customization and theming
All dialogs accept common parameters to match your appâs style:
- shape, titlePadding, contentPadding, actionsPadding, insetPadding
- width, height (where applicable)
- headerBuilder and dayBuilder for custom header/day cell UIs
- firstDate and lastDate to constrain selectable dates
The dateâtime dialog also exposes formatString to control the live preview text (the returned value is still a DateTime).
Behavior and notes
- All pickers support output in āļ.āļĻ. or āļ.āļĻ. via the
eraparameter. - The calendar respects
firstDateandlastDateand disables days outside this window. - For localized month/weekday names, initialize locale once on startup via
ThaiDateService().initializeLocale('th_TH').
Error handling and edge cases
- Parsing uses a simple heuristic for BE years (>= 2400). If your input is ambiguous or uses a custom pattern, prefer
ThaiDateService().parseWithEra(input, pattern: '...', era: Era.be|Era.ce)or pass an explicitformat:toparse. - All UI pickers are timezone-agnostic and operate on
DateTimevalues you provide; be mindful of UTC vs local when storing or comparing. - The tokenâaware formatter replaces only year tokens; other tokens are left to
intlfor correct localization.
Notes
- Tokenâaware: only year tokens (
y,yy,yyyy) are swapped to BE; other tokens are left tointlfor correct localization. - Parsing heuristics treat years
>= 2400as BE. If inputs are ambiguous, useThaiDateService().parseWithEra(..., era: ...)with an explicit pattern. - For Thai month/day names in Flutter, initialize locale via
ThaiDateService().initializeLocale('th_TH')before rendering widgets.
License
MIT
āļ§āļīāļāļĩāđāļāđāļāļēāļ (āļ āļēāļĐāļēāđāļāļĒ)
āļāđāļēāļāļĨāđāļēāļāļāļĩāđāļāļ·āļāļāļđāđāļĄāļ·āļāļāļēāļĢāđāļāđāļāļēāļāđāļāļāļĒāđāļāļāļĢāđāļāļĄāļāļąāļ§āļāļĒāđāļēāļāđāļāđāļāļāļĢāļāļāļāļĨāļļāļĄāļāļĢāļāļĩāļāļąāđāļ§āđāļ āđāļĨāļ°āļāļēāļĢāļāļąāđāļāļāđāļēāđāļāļīāđāļĄāđāļāļīāļĄ
1) āļāļēāļĢāđāļĢāļĩāļĒāļāđāļāđāļāļēāļāļāļāļāļī (Standard)
āđāļāđ parse āļāđāļēāļāļŠāļāļĢāļīāļāļ§āļąāļāļāļĩāđāđāļāđāļ BE/CE āđāļāđāļāļąāļāđāļāļĄāļąāļāļī āđāļĨāļ° format āđāļāļ·āđāļāļāļīāļĄāļāđāļāļĨ āđāļāļĒāđāļĨāļ·āļāļāļĒāļļāļāļāļĩāļāđāļ§āļĒ era: Era.be|Era.ce
import 'package:thai_buddhist_date/thai_buddhist_date.dart';
final dt1 = parse('2568-08-25'); // āļāļīāļāļāļļāļ āļ.āļĻ. -> āļ āļēāļĒāđāļāđāļāđāļ āļ.āļĻ. (2025-08-25)
final dt2 = parse('2025-08-25'); // āļāļīāļāļāļļāļ āļ.āļĻ.
final sBE = format(dt1); // āļāđāļēāđāļĢāļīāđāļĄāļāđāļ Era.be -> 2568-08-25
final sCE = format(dt1, era: Era.ce); // 2025-08-25
āđāļāđāđāļāļāđāļāļīāļĢāđāļāđāļāļāđāļāđ āđāļāđāļ MMMM yyyy, dd/MM/yyyy, HH:mm āđāļāđāļāļāđāļ
final d = DateTime(2025, 8, 25);
print(format(d, format: 'dd/MM/yyyy')); // 25/08/2568 (BE)
print(format(d, format: 'MMMM yyyy')); // āļŠāļīāļāļŦāļēāļāļĄ 2568 (BE)
print(format(d, format: 'MMMM yyyy', era: Era.ce)); // āļŠāļīāļāļŦāļēāļāļĄ 2025 (CE)
// āļ§āļąāļāļāļĩāđāđāļāļ formatNow (āđāļĄāđāļāđāļāļ await)
print(formatNow(pattern: 'MMMM yyyy'));
2) āļāļēāļĢāđāļĢāļĩāļĒāļāđāļāđāļāļēāļāļāļĒāđāļēāļāļāđāļēāļĒ (Quick)
- āđāļĄāđāļāļĒāļēāļāļŠāļĢāđāļēāļ
DateTime.now()āđāļāļ āđāļāđformatNow(...) - āļāđāļāļāļāļēāļĢāļāļ·āđāļāđāļāļ·āļāļ/āļ§āļąāļāđāļāļ localized āđāļŦāđāđāļĢāļĩāļĒāļ
ThaiDateService().initializeLocale('th_TH')āļŦāļāļķāđāļāļāļĢāļąāđāļāļāđāļāļāđāļāđāļāļēāļ - āđāļāđ extension āļŠāļģāļŦāļĢāļąāļ
DateTime
// āļāđāļēāļĒāļāđāļāļāļ§āļēāļĄāļāļāļāļāļĩāđ (āđāļĄāđāļāđāļāļ await)
final label = formatNow(pattern: 'fullText');
// āđāļŦāļĨāļ locale āļāđāļāļāđāļĨāđāļ§āļāđāļāļĒāđāļāđāļāļēāļ
await ThaiDateService().initializeLocale('th_TH');
final labelAfterInit = formatNow(pattern: 'fullText');
// Extension āļāļ DateTime
final pretty = DateTime(2025, 8, 25).toThaiStringSync(pattern: 'yyyy-MM-dd');
// āļ§āļąāļāļāļĩāđāđāļāļāđāļĢāđāļ§
final todayQuick = formatNow(pattern: 'yyyy-MM-dd');
3) āļāļēāļĢāđāļĢāļĩāļĒāļāđāļāđāļāļēāļāđāļāļ Custom (āļŠāļĨāļąāļ/āļāļąāļāļŠāđāļ§āļ, āđāļāļ·āļāļāļĒāđāļ, āļāļąāļ§āļāļąāđāļ)
āļāđāļāļāļāļēāļĢāļĢāļđāļāđāļāļ âāļ§āļąāļ āđāļāļ·āļāļ āļāļĩâ āđāļāđāļ 25 āļŠāļīāļāļŦāļēāļāļĄ 2568 āđāļāđāļāļĢāļĩāđāļāđāļ pattern: 'dmy'
final d = DateTime(2025, 8, 25);
print(format(d, pattern: 'dmy')); // 25 āļŠāļīāļāļŦāļēāļāļĄ 2568
print(format(d, pattern: 'dmy', era: Era.ce)); // 25 āļŠāļīāļāļŦāļēāļāļĄ 2025
// āļ§āļąāļāļāļĩāđāļāđāļ§āļĒāļāļĢāļĩāđāļāđāļāđāļāļĩāļĒāļ§āļāļąāļ
print(formatNow(pattern: 'dmy'));
āļŦāļĢāļ·āļāļāļģāļŦāļāļāđāļāļāđāļāļīāļĢāđāļāđāļāļ āđāļāđāļ MMMM d, d MMMM, d MMM yyyy
// āđāļĢāļĩāļĒāļ āļ§āļąāļ āđāļāļ·āļāļ āļāļĩ (āļāļĩāļāļāļĨāļāđ)
final def = format(d, pattern: 'd MMMM yyyy', era: Era.be); // 25 āļŠāļīāļāļŦāļēāļāļĄ 2568
// āļŠāļĨāļąāļāđāļāđāļ āđāļāļ·āļāļ āļ§āļąāļ
final monthDay = format(d, pattern: 'MMMM d', era: Era.be); // āļŠāļīāļāļŦāļēāļāļĄ 25
// āļāļąāļāļāļĩāļāļāļ (āļ§āļąāļ āđāļāļ·āļāļ)
final dayMonth = format(d, pattern: 'd MMMM', era: Era.be); // 25 āļŠāļīāļāļŦāļēāļāļĄ
// āđāļāđāđāļāļ·āļāļāļĒāđāļ
final shortDash = format(d, pattern: 'd MMM yyyy', era: Era.be); // 25 āļŠ.āļ. 2568
4) āđāļāđāļāļēāļāļāđāļ§āļĒ āļ.āļĻ. āļŦāļĢāļ·āļ āļ.āļĻ. (Formatting & Parsing with Era)
- Formatting: āļāļģāļŦāļāļāļĒāļļāļāļāļĩāļāđāļ§āļĒ
era: Era.be|Era.ceāđāļformat(...)āļŦāļĢāļ·āļ extensiontoThaiString(...) - Parsing (āļāļīāļāļāļļāļāđāļāđāļāļąāļāļ§āđāļēāđāļāđāļ āļ.āļĻ.): āđāļāđ
ThaiDateService().parseWithEra(..., era: Era.be)āđāļāļ·āđāļāļāļąāļāļāļąāļāđāļāļĨāļāļāļĩ āļ.āļĻ. -> āļ.āļĻ.
// Formatting āđāļāđāļ āļ.āļĻ. āļŦāļĢāļ·āļ āļ.āļĻ.
final be = format(d); // 2568-08-25
final ce = format(d, era: Era.ce); // 2025-08-25
// āļ§āļąāļāļāļĩāđ (BE/CE)
print(formatNow(pattern: 'yyyy-MM-dd', era: Era.be));
print(formatNow(pattern: 'yyyy-MM-dd', era: Era.ce));
// Parsing āđāļĄāļ·āđāļāļāļīāļāļāļļāļāđāļāđāļ āļ.āļĻ. āđāļāđāļāļāļ
final parsedBE = ThaiDateService().parseWithEra(
'25 āļŠāļīāļāļŦāļēāļāļĄ 2568',
pattern: 'd MMMM yyyy',
era: Era.be,
); // -> DateTime(2025, 8, 25)
5) āļŦāļĨāļēāļĒāļ āļēāļĐāļē (Multiâlanguage)
- āļāļģāļŦāļāļ locale āđāļāđāļāļĢāļēāļĒāļāļĢāļąāđāļāļāđāļēāļ
locale: 'th_TH' | 'en_US' | 'ja' | ... - āļāļąāđāļāļāđāļēāļ āļēāļĐāļē/locale āļāļąāđāļāļĢāļ°āļāļāļāđāļ§āļĒ
ThaiDateService().setLanguage(...)āļŦāļĢāļ·āļinitializeLocale(...)
await ThaiDateService().initializeLocale('ja');
final jaNow = await ThaiDateService().formatNow(pattern: 'fullText', locale: 'ja');
6) āļāļīāļāļŠāđ (Tips)
ThaiDateService().formatSync(...)āđāļĢāđāļ§āļŠāļģāļŦāļĢāļąāļāđāļāļāđāļāļīāļĢāđāļāđāļāļīāļāļāļąāļ§āđāļĨāļāļĨāđāļ§āļ- Extensions:
DateTime.toThaiString(),String.toThaiDate()