TFormatSettings 简介
TFormatSettings 是日期时间、货币、数字的格式,全局对象 FormatSettings 就是这个类型的。
• 如果统一更改应用程序当前进程之内的日期时间、或者货币、数字的格式,需要用全局对象 FormatSettings,
• 如果给某个函数临时使用,或者应用程序里面维护几套不同的格式,可以创建与全局对象的数据不同的 TFormatSettings 对象。
• 格式涉及到的控制符请参考 FormatDateTime 函数说明里面的 “格式控制符” 表格。
• 属性 • 方法 • 事件
头文件:
#include <System.SysUtils.hpp> (XE2 之后),#include <SysUtils.hpp> (XE 之前)
命名空间:
System::Sysutils
继承关系:
无
例:用 TFormatSettings::Create 函数创建一个特定地区的格式信息
LCID lcid = MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN); // 日本
TFormatSettings fs = TFormatSettings::Create(lcid); // 创建一个格式信息 fs |
如果按照上面的方法创建 fs,则不包含那个地区的 EraInfo 本地日历信息,一般用途足够了。
经过测试,TFormatSettings::Create 方法是通过当前线程的地区和语言获取的 EraInfo 本地日历信息,如下代码:
LCID lcid = MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN); // 日本
LCID lcidOld = GetThreadLocale(); // 获取当前线程的地区和语言
SetThreadLocale(lcid); // 修改当前线程的地区和语言
TFormatSettings fs = TFormatSettings::Create(lcid); // 创建一个格式信息 fs
SetThreadLocale(lcidOld); // 恢复当前线程的地区和语言 |
创建 fs 之后,就可以立即恢复线程的地区和语言了,只要 fs 对象不被修改和销毁,会一直维持获取的地区和语言信息。
通过继续的测试,即便是 fs 没有丢失数据,也没有被销毁,但是 FormatDateTime 函数始终依照 GetThreadLocale 获取到的信息,而不是依照参数 fs 来生成 era 信息。通过查看源码,发现 FormatDateTime 的 era 信息是通过 Windows API 函数 GetDateFormat(GetThreadLocale(), DATE_USE_ALT_CALENDAR, st, fmt, str, cchstr); 来实现的,并没有处理 fs 信息。GetDateFormat 的第一个参数始终用的是 GetThreadLocale()。
所以,只有当需要获取 EraInfo 本地日历信息的时候,才需要更改线程的地区和语言信息,否则使用第一段代码就足够了。
EraInfo 本地日历信息表:
EraInfo 为本地日历信息表,如果本地有和西元/公元不同的日历,会反映在这个列表里面。
有关 era 的描述,可以参考维基百科的 Calendar era 这篇文章,链接请点击:https://en.wikipedia.org/wiki/Calendar_era
TFormatSettings::TEraInfo 类型的定义:
struct TEraInfo
{
public:
UnicodeString EraName;
int EraOffset;
TDate EraStart;
TDate EraEnd;
}; |
数据 |
类型 |
描述 |
public: |
|
|
EraName |
UnicodeString |
日历的纪元名称,例如:L"平成"、L"昭和"、L"단기" |
EraOffset |
int |
日历开始纪元的年,例如 1989, 1926, 2333 |
EraStart |
TDate |
日历的日期范围:开始日期,经过测试,发现日本和韩国有 EraInfo,这个数值都是 0 |
EraEnd |
TDate |
日历的日期范围:结束日期,经过测试,发现日本和韩国有 EraInfo,这个数值都是 0 |
在日本,EraOffset 和 GetEraYearOffset(L"平成") 返回的是 1989,GetEraYearOffset(L"昭和") 返回的是 1926;
在韩国,EraOffset 和 GetEraYearOffset(L"단기") 返回的是 2333,按理说단군기원是西元前 2333 年,可是没有通过符号反映出来;
经过测试,通过 Windows API 函数 EnumCalendarInfo 获取的数值,仍然是没有符号的,这说明这个值作为计算依据是有问题的。
实际测试,FormatDateTime 函数返回的 era 年代是对的,通过查看源码,发现 FormatDateTime 的 era 信息是通过 Windows API 函数 GetDateFormat(GetThreadLocale(), DATE_USE_ALT_CALENDAR, st, fmt, str, cchstr); 来实现的,并没有处理 FormatSettings 信息,即使给了这个参数。GetDateFormat 的第一个参数始终用的是 GetThreadLocale()。
用 FormatDateTime 函数显示或计算本地日历的年份
利用 FormatDateTime 可以得到本地日历的年份。FormatDateTime 函数始终使用 GetThreadLocale() 获取线程的地区和语言用作 era 本地日历,而不会去使用函数的 FormatSettings 参数。
格式 L"g" 和 L"gg" 是获取纪元名称的,例如 L"平成",L"단기"
格式 L"e", L"ee" 和 L"eeee" 是获取纪元年代的,是整数值,超过 2 位的年需要用 L"eeee",而 L"e" 和 L"ee" 只获取到最多 2 位的年。
例如:在韩国,2017 年是 “단기4350”
dt = TDateTime(2017, 7, 6);
s = FormatDateTime(L"ggee", dt);
和
s = FormatDateTime(L"ggeeee", dt);
分别得到 L"단기50" 和 L"단기4350"
例如:在日本,2017 年是 “平成29”
dt = TDateTime(2017, 7, 6);
s = FormatDateTime(L"ge", dt);
和
s = FormatDateTime(L"ggeeee", dt);
都将得到 L"平成29"
用 Windows API 函数获取本地日历的年份
void __fastcall TForm1::Button4Click(TObject *Sender)
{
SYSTEMTIME st;
memset(&st, 0, sizeof(st));
st.wYear = 2017; st.wMonth = 7; st.wDay = 6; // 2017年7月6日
LCID lcid;
wchar_t buf[32];
lcid = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN); // 韩国
GetDateFormat(lcid, DATE_USE_ALT_CALENDAR, &st, L"ggyyyy", buf, 32);
Memo1->Lines->Add(buf);
lcid = MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN); // 日本
GetDateFormat(lcid, DATE_USE_ALT_CALENDAR, &st, L"ggyyyy", buf, 32);
Memo1->Lines->Add(buf);
} |
运行结果:
自己计算本地日历的年份
开始纪元的年代在西元前的计算区别:
西元 n 年开始纪元的,按照现在的日期计算,那个日历纪元的年 = 西元年 - n + 1 年,例如 2017 年是平成 29 年,2017 - 1989 + 1 = 29;
西元前 n 年开始纪元的,按照现在的日期计算,那个日历纪元的年 = 西元年 + n 年,例如 2017 年是단기 4350 年,2017 + 2333 = 4350。
西元年 |
西元前3年 |
西元前2年 |
西元前1年 |
西元元年,西元0001年 |
西元0002年 |
西元0003年 |
西元xxxx年 |
|
|
开始纪元 (元年) |
第 2 年 |
第 3 年 |
第 4 年 |
第 5 年 |
第 xxxx+2 年 |
计算中国日历的年份,例如 2017 年 = 丁酉(鸡) 年
黄帝历是从西元前 2697 年开始纪元的,EraOffset 就是 2697,西元 2017 年相当于黄帝纪元 4714 年 (2017 + 2697 = 4714),
道历纪元与黄帝纪元相同,也是西元前 2697 年开始纪元的。
目前大多数人认为中国日历是从西元前 2697 年开始计算的,也有人认为是从西元前 2637 年开始的,他们之间差距 60 年,是干支纪年的一个循环周期。由于古代历法一直使用干支纪年,很少提及开始纪元的年代,所以根据古代的记载推算开始纪元的年代差一个周期甚至 n 个周期 (差 60 或 n 个 60 年) 也很容易理解。无论用哪个数据,计算出来的干支纪年的结果都是一样的。
有关 era 和中国日历的描述,可以参考维基百科的 Calendar era 这篇文章,链接请点击:https://en.wikipedia.org/wiki/Calendar_era
维基百科里面有关中国日历的另一篇文章 Chinese calendar,链接请点击:https://en.wikipedia.org/wiki/Chinese_calendar
中国日历最常用的是甲子、乙丑……这样的干支纪年方法,是从黄帝历纪元开始计算的,1年=甲子(鼠)年,2年=乙丑(牛)年……,具体计算方法:
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 (整除无余数) |
天干 = 黄帝纪元 % 10 (除以10的余数) |
甲 |
乙 |
丙 |
丁 |
戊 |
己 |
庚 |
辛 |
壬 |
癸 |
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 (整除无余数) |
地支 = 黄帝纪元 % 12 (除以12的余数) |
子 |
丑 |
寅 |
卯 |
辰 |
巳 |
午 |
未 |
申 |
酉 |
戌 |
亥 |
生肖 = 与地支对应 |
鼠 |
牛 |
虎 |
兔 |
龙 |
蛇 |
马 |
羊 |
猴 |
鸡 |
狗 |
猪 |
2017 年 → 加上 2697 = 黄帝纪元 4714 年
→ 4714 % 10 = 4,即第 4 个天干 = 丁
→ 4714 % 12 = 10,即第 10 个地支(生肖) = 酉(鸡)
→ 2017 年为丁酉(鸡) 年
|