:: 포맷팅 ::
수치 서식 문자열
G : 일반(지수 표기 대문자)
g : 일반(지수 표기 소문자)
F : 고정 소수점
N : 그룹 구분자가 있는 고정 소수점
D : 선행 자리수를 0으로 채움
E : 지수 표기(대문자)
e : 지수 표기(소문자)
C : 통화
P : 퍼센트
X : 16진수(대문자)
x : 16진수(소문자)
R : 순환소수(복원 가능)
* float이나 double의 정밀도 한계에 놓인 두 유효숫자는 버려지나, R이나 G17은 버리지 않는다.
* .NET 4.6 이상에서 R과 G17은 같은 일을 함.
* 그 이전 버전에서는 R은 G17의 버그 있는 버전이므로 사용 하지 말 것.
커스텀 수치 서식 문자열
# : 숫자 자리표, 소수점 이하 자릿수를 #수만큼 제한함
0 : 0 자리표, 소수점 이전과 이후의 빈 자리에 0들을 채움.
. : 소수점
, : 그룹 구분자(ex: #,###,###)
, : 승수(ex: #,,), 1000이나 1000000등으로 나눈 결과
% : 퍼센트 표기, 100을 곱하고 퍼센트 기호를 붙힘
E0, e0, E+0, e+0, E-0, e-0: 지수 표기
\ : 리터럴 문자 인용, @ 접두사가 없는 문장에서는 \\
' ' : 리터럴 문자열 인용
; : 섹션 구분자
:: 파싱 ::
(System.Globalization.Numberstyle)
- 플래그 열거형(Flags 특성이 지정된 enum)
- 문자열을 수치 형식으로 변환할 때 적용되는 규칙들을 지정
1. 일반 멤버
- AllowLeadingWhite: 앞쪽에 일련의 공백이 올 수 있음
- AllowTrailingWhite: 뒤쪽에 일련의 공백이 올 수 있음
[ 인식하는 공백 문자, IsWhiteSpace가 true를 반환하는 문자 집단의 부분집합 ]
* CHARACTER TABULATION (U+0009)
* LINE FEED (U+000A)
* LINE TABULATION (U+000B)
* FORM FEED (U+000C)
* CARRIAGE RETURN (U+000D)
* SPACE (U+0020)
- AllowLeadingSign: 앞쪽에 부호 문자가 올 수 있음
- AllowTrailingSign: 뒤쪽에 부호 문자가 올 수 있음
* NumberFormatInfo.PositiveSign: 양수 기호
* NumberFormatInfo.NegativeSign: 음수 기호
- AllowParentheses: 숫자를 둘러싸는 괄호가 존재 할 수 있음
- AllowThousands: 숫자에 단위 구분 기호가 존재 할 수 있음
* NumberFormatInfo.CurrencyGroupSeparator: 통화 기호 포함시, 단위 구분자
* NumberFormatInfo.CurrencyGroupSizes: 통화 기호 포함시, 단위 자릿수
* NumberFormatInfo.NumberGroupSeparator: 일반, 단위 구분자
* NumberFormatInfo.NumberGroupSizes: 일반, 단위 자릿수
- AllowCurrencySymbol: 숫자에 통화 기호가 포함 될 수 있음
* NumberFormatInfo.CurrencySymbol
- AllowDecimalPoint: 소수점이 포함 될 수 있음
* NumberFormatInfo.CurrencyDecimalSeparator: 통화 기호 포함시, 소수 구분자
* NumberFormatInfo.NumberDecimalSeparator: 일반, 소수 구분자
- AllowExponent: 지수 표현식이 포함 될 수 있음 (nEx, nE+x, nE-x, nex, ne+x, ne-x)
- AllowHexSpecifier: 숫자 문자열이 16진수 값을 나타냄
* 대소문자 구별 없음
* 0x, &h와 같은 접미사가 들어간 문자열은 인식하지 못함(예외 발생)
2. 합성 멤버
- Integer: LS
- Float: LS, DP, E
- Number: LS, TS, DP, T
- HexNumber: HS
- Currency: LS, TS, P, DP, T, CS
- Any: LS, TS, P, DP, T, E, CS
3. 자료형에 따른 기본 값
- 정수형: LS
- double, float: LS, DP, T, E
- decimal: LS, TS, DP, T
:: 포맷팅 ::
날짜 및 시간 서식 문자열
- DateTime이나 DateTimeOffset을 위한 서식 문자열
1. 문화권 감지
d : 짧은 날짜
D : 긴 날짜
t : 짧은 시간
T : 긴 시간
f : 긴 날짜 + 짧은 시간
F : 긴 날짜 + 긴 시간
g : 짧은 날짜 + 짧은 시간
G : 짧은 날짜 + 긴 시간 (기본값)
m, M : 월과 일
y, Y : 연도와 월
2. 문화권 무시
o : 복원 가능
- DateTimeKind가 Unspecified가 아닌 한, 시간대 정보를 붙힘
r, R : RFC 1123 표준,
- UTC를 고려한 시간대 접미사를 붙힘
- 지역 시간을 UTC로 자동 변환하지 않기 때문에 DateTime.ToUniversalTime을 이용해서 명시적으로 UTC로 변환해줘야 한다.
s : 정렬 가능 ISO 8601, 텍스트 기반 정렬 지원
u : 정렬 가능 UTC, 텍스트 기반 정렬 지원
- 지역 시간을 UTC로 자동 변환하지 않기 때문에 DateTime.ToUniversalTime을 이용해서 명시적으로 UTC로 변환해줘야 한다.
U : UTC, UTC로 변환된 긴 날짜 + 짧은 시간
- 지역 시간을 UTC로 자동 변환
3. 커스텀 수식 문자열
g, gg : 캘린더에 따른 시대(era)명
y: 년도 중 뒷 두자리만 표시
yy : 년도 중 뒷 두자리만 표시 (0 채움)
yyyy : 년도를 전체 표시
M : 월
MM : 월 (0 채움)
MMM : 문화권에 따른 단축된 월명
MMMM : 문화권에 따른 월명
d : 일
dd : 일 (0 채움)
ddd : 문화권에 따른 단축된 요일명
dddd : 문화권에 따른 요일명
t : AM/PM (약자)
tt : AM/PM
h : 시간 (12시간제)
hh : 시간 (0 채움, 12시간제)
H : 시간 (24시간제)
HH : 시간 (0 채움, 24시간제)
m : 분
mm : 분 (0 채움)
s : 초
ss : 초 (0 채움)
: : 시간 구분자
/ : 날짜 구분자
:: 파싱 ::
DateTime의 파싱 및 파싱 오해
- 일이나 월이 연도보다 앞인 날짜 문자열은 중의적(월과 일을 서로 바꿔 인식할 수 있음)이기에 오해 발생
- 해결법
* 서식화와 파싱을 수행 할 때 항상 동일한 문화권을 명시적으로 지정
* DateTime과 DateTimeOffset을 문화권에 독립적인 방식으로 서식화
("o"같은 문화권과 별도로 표준화된 서식 문자열을 쓰면 더 좋다)
DateTimeStyles 열거형
(System.Globalization.Datetimestyles)
- 플래그 열거형(Flags 특성이 지정된 enum)
- DateTimeOffset에 Parse를 호출 할 때 서식에 대한 추가적인 지시사항을 제공
- None: 기본 값
- AdjustToUniversal: Local 시간을 UTC 시간으로 변환. Local인지 UTC인지 알 수 없으면 변환하지 않고 Unspecified로.
- AllowInnerWhite: 패턴에 포함된 공백을 제외하고, 문자열 중간의 추가 공백 문자를 무시
- AllowLeadingWhite: 패턴에 포함된 공백을 제외하고, 문자열 처음의 공백 문자를 무시
- AllowTrailingWhite: 패턴에 포함된 공백을 제외하고, 문자열 마지막의 공백 문자를 무시
- AllowWhiteSpaces: 패턴에 포함된 공백을 제외하고, 모든 공백 문자를 무시 (AIW + ALW + ATW)
- AssumeLocal: 표준 시간대가 지정되지 않은 경우 Local 시간대인 것으로 가정
- AssumeUniversal: 표준 시간대가 지정되지 않은 경우 UTC인것으로 가정
- NoCurrentDateDefault: 시간만 있는 경우, 0001년 01월 01로 가정함
- RoundtripKind: "o", "r" 같이 시간대 정보(DateTimeKind)가 저장된 텍스트일 경우 그를 복원하기 위해 사용
(정확한 사용 용도를 모르겠음...)
:: 포맷팅 ::
열거형 서식 문자열
G, g : 일반
F, f: enum에 Flags 특성이 적용된 것 처럼 취급
D, d: 십진수
X, x: 십육진수
using System;
using System.Globalization;
using System.Text;
namespace Practice
{
class Program
{
static void Main(string[] args)
{
int max = 17;
// 정수형에만 적용되는 표준 수치 서식 문자열
char[] charForInt = "DXx".ToCharArray();
int IntData = 129123456;
foreach (char item in charForInt)
{
formatPrinter(IntData, item, max);
}
// 실수형에서도 적용 가능한 표준 수치 서식 문자열
char[] charForDouble = "GgFNEeCP".ToCharArray();
double doubleData = 1293.9150149231657317248;
foreach (char item in charForDouble)
{
formatPrinter(doubleData, item, max);
}
formatPrinter(doubleData, 'R', -1);
// 커스텀 수치 문자열
double customData = 1230.456789;
formatSimplePrinter(customData, ".##"); // 숫자 자리표
formatSimplePrinter(customData, "000000.000000"); // 0자리표
formatSimplePrinter(customData, "#,#"); // 그룹 구분자
formatSimplePrinter(customData, "#,"); // 승수
formatSimplePrinter(customData, "00%"); // 퍼센트
formatSimplePrinter(customData, "000E+0"); // 지수 표기
formatSimplePrinter(customData, "\\#.00"); // 리터럴 문자 인용
formatSimplePrinter(customData, "'...'.00"); // 리터럴 문자열 인용
formatSimplePrinter(0, "0;(0);zero"); // 섹션 구분자
formatSimplePrinter(-1, "0;(0);zero"); // 섹션 구분자
formatSimplePrinter(1, "0;(0);zero"); // 섹션 구분자
// NumberStyles 열거형
// 일반 멤버
Console.WriteLine(int.Parse(" 45", NumberStyles.AllowLeadingWhite));
Console.WriteLine(int.Parse("45 ", NumberStyles.AllowTrailingWhite));
Console.WriteLine(int.Parse("-45", NumberStyles.AllowLeadingSign));
Console.WriteLine(int.Parse("45-", NumberStyles.AllowTrailingSign));
Console.WriteLine(int.Parse("(45)", NumberStyles.AllowParentheses));
Console.WriteLine(int.Parse("45,000,000", NumberStyles.AllowThousands));
Console.WriteLine(int.Parse("\\1000", NumberStyles.AllowCurrencySymbol));
Console.WriteLine(double.Parse("45.101", NumberStyles.AllowDecimalPoint));
Console.WriteLine(decimal.Parse("3e+6", NumberStyles.AllowExponent));
Console.WriteLine(int.Parse("3aC", NumberStyles.AllowHexSpecifier));
Console.WriteLine();
// 합성 멤버
Console.WriteLine(int.Parse(" 2", NumberStyles.Integer));
Console.WriteLine(double.Parse("22.44", NumberStyles.Float));
Console.WriteLine(int.Parse("1,000,000", NumberStyles.Number));
Console.WriteLine(int.Parse("4ac", NumberStyles.HexNumber));
Console.WriteLine(double.Parse("\\(5.20)", NumberStyles.Currency));
Console.WriteLine(decimal.Parse("3e6", NumberStyles.Any));
Console.WriteLine();
// 자료형에 따른 기본 값
Console.WriteLine(int.Parse(" 2"));
Console.WriteLine(double.Parse("1,222.44"));
Console.WriteLine(decimal.Parse("3-"));
Console.WriteLine();
// 커스텀
NumberFormatInfo ni = new NumberFormatInfo();
ni.CurrencySymbol = "$";
ni.CurrencyGroupSeparator = " ";
double million = double.Parse("$1 000 000", NumberStyles.Currency, ni);
Console.WriteLine();
// 날짜-시간 서식 문자열
// DateTime, DateTime 열거형
DateTime DTNow = DateTime.Now;
// 문화권 감지
char[] charForDateTimeLocal = "dDtTfFgGmMyY".ToCharArray();
foreach (var item in charForDateTimeLocal)
{
formatSimplePrinter(DTNow, item);
}
Console.WriteLine();
// 문화권 무시
char[] charForDateTimeInvariant = "orRsuU".ToCharArray();
foreach (var item in charForDateTimeInvariant)
{
formatSimplePrinter(DTNow, item);
}
Console.WriteLine();
// 커스텀
formatSimplePrinter(DTNow, "g y/M/d(ddd) tt h:m:s");
formatSimplePrinter(DTNow, "gg");
formatSimplePrinter(DTNow, "yyyy");
formatSimplePrinter(DTNow, "yy");
formatSimplePrinter(DTNow, "MMMM");
formatSimplePrinter(DTNow, "MMM");
formatSimplePrinter(DTNow, "MM");
formatSimplePrinter(DTNow, "dddd");
formatSimplePrinter(DTNow, "ddd");
formatSimplePrinter(DTNow, "dd");
formatSimplePrinter(DTNow, "tt");
formatSimplePrinter(DTNow, "hh");
formatSimplePrinter(DTNow, "HH");
formatSimplePrinter(DTNow, "mm");
formatSimplePrinter(DTNow, "ss");
//DateTime의 파싱 및 파싱 오해
//"o" 서식을 이용한 파싱
string s = DateTime.Now.ToString("o");
// 가능하다면 ParseExact를 쓰는것이 낫다.
// 잘못 파싱되는 쪽 보다 예외를 뿜어내는 쪽이 더 나은 편.
DateTime DT1 = DateTime.ParseExact(s, "o", null);
DateTime DT2 = DateTime.Parse(s);
// DateTimeStyles 열거형
CultureInfo IC = CultureInfo.InvariantCulture;
Console.WriteLine(DateTime.Parse("01:12:23", IC, DateTimeStyles.None));
Console.WriteLine(DateTime.Parse("01:12:23 +09:00", IC, DateTimeStyles.AdjustToUniversal));
Console.WriteLine(DateTime.Parse(" 01 : 12 : 23 ", IC, DateTimeStyles.AllowWhiteSpaces));
Console.WriteLine(DateTime.Parse("01:12:23", IC, DateTimeStyles.AssumeLocal));
Console.WriteLine(DateTime.Parse("01:12:23", IC, DateTimeStyles.AssumeUniversal));
Console.WriteLine(DateTime.Parse("01:12:23", IC, DateTimeStyles.NoCurrentDateDefault));
Console.WriteLine(DateTime.Parse(s, IC, DateTimeStyles.RoundtripKind));
// 열거형 서식 문자열
string[] stringForEnum = "G g F f D d X x".Split();
foreach (var item in stringForEnum)
{
Console.WriteLine(DateTimeStyles.AllowWhiteSpaces.ToString(item));
}
}
static void formatPrinter(dynamic data, char formatChar, int max)
{
int index = 0;
StringBuilder sb = new StringBuilder();
string[] formatString = new string[max + 2];
for (int i = 0; i < formatString.Length; i++)
{
sb.Clear();
sb.Append("{");
sb.Append(index);
sb.Append(":");
sb.Append(formatChar);
if (i != 0)
{
sb.Append(i - 1);
}
sb.Append("}");
formatString[i] = sb.ToString();
Console.Write((formatString[i] + ": ").PadLeft(20));
Console.WriteLine(formatString[i], data);
}
Console.WriteLine();
}
static void formatSimplePrinter(dynamic data, string format)
{
int index = 0;
string formatString;
StringBuilder sb = new StringBuilder();
sb.Append("{");
sb.Append(index);
sb.Append(":");
sb.Append(format);
sb.Append("}");
formatString = sb.ToString();
Console.Write((formatString + ": ").PadLeft(20));
Console.WriteLine(formatString, data);
}
static void formatSimplePrinter(dynamic data, char format)
{
formatSimplePrinter(data, format.ToString());
}
}
}
'C#' 카테고리의 다른 글
[C#] BitConverter (1) | 2023.08.17 |
---|---|
[C#] XmlConvert (1) | 2023.08.16 |
[C#] Convert (2) | 2023.08.15 |
[C#] 서식화(Formatting)와 파싱(Parsing) (1) | 2023.08.14 |
[C#] TimeZoneInfo.AdjustmentRule & TimeZoneInfo.TransitionTime (1) | 2023.08.12 |
[C#] TimeZoneInfo (1) | 2023.08.11 |
[C#] TimeZone (1) | 2023.08.10 |
[C#] DateTime & DateTimeOffset (0) | 2023.07.06 |