public string format()
{
StringBuilder s = new StringBuilder();
int len = pattern.Length;
for (int i=0; i<len; ++i)
{
// character
int c = pattern[i];
// literals
if (c == '\'')
{
while (true)
{
++i;
if (i >= len) throw ArgErr.make("Invalid pattern: unterminated literal").val;
c = pattern[i];
if (c == '\'') break;
s.Append((char)c);
}
continue;
}
// character count
int n = 1;
while (i+1<len && pattern[i+1] == c) { ++i; ++n; }
// switch
bool invalidNum = false;
switch (c)
{
case 'Y':
int y = this.year;
switch (n)
{
case 2: y %= 100; if (y < 10) s.Append('0'); s.Append(y); break;
case 4: s.Append(y); break;
default: invalidNum = true; break;
}
break;
case 'M':
if (mon == null) throw ArgErr.make("Month not available").val;
switch (n)
{
case 4:
s.Append(mon.full(locale()));
break;
case 3:
s.Append(mon.abbr(locale()));
break;
case 2: if (mon.ordinal()+1 < 10L) s.Append('0'); s.Append(mon.ordinal()+1); break;
case 1: s.Append(mon.ordinal()+1); break;
default: invalidNum = true; break;
}
break;
case 'D':
switch (n)
{
case 3: s.Append(day).Append(daySuffix(day)); break;
case 2: if (day < 10) s.Append('0'); s.Append(day); break;
case 1: s.Append(day); break;
default: invalidNum = true; break;
}
break;
case 'W':
if (weekday == null) throw ArgErr.make("Weekday not available").val;
switch (n)
{
case 4:
s.Append(weekday.full(locale()));
break;
case 3:
s.Append(weekday.abbr(locale()));
break;
default: invalidNum = true; break;
}
break;
case 'V':
int woy = weekOfYear();
if (woy < 1) throw ArgErr.make("Week of year not available").val;
switch (n)
{
case 3: s.Append(woy).Append(daySuffix(woy)); break;
case 2: if (woy < 10) s.Append('0'); s.Append(woy); break;
case 1: s.Append(woy); break;
default: invalidNum = true; break;
}
break;
case 'h':
case 'k':
int h = this.hour;
if (c == 'k')
{
if (h == 0) h = 12;
else if (h > 12) h -= 12;
}
switch (n)
{
case 2: if (h < 10) s.Append('0'); s.Append(h); break;
case 1: s.Append(h); break;
default: invalidNum = true; break;
}
break;
case 'm':
switch (n)
{
case 2: if (min < 10) s.Append('0'); s.Append(min); break;
case 1: s.Append(min); break;
default: invalidNum = true; break;
}
break;
case 's':
switch (n)
{
case 2: if (sec < 10) s.Append('0'); s.Append(sec); break;
case 1: s.Append(sec); break;
default: invalidNum = true; break;
}
break;
case 'S':
if (sec != 0 || ns != 0)
{
switch (n)
{
case 2: if (sec < 10) s.Append('0'); s.Append(sec); break;
case 1: s.Append(sec); break;
default: invalidNum = true; break;
}
}
break;
case 'a':
switch (n)
{
case 1: s.Append(hour < 12 ? "a" : "p"); break;
case 2: s.Append(hour < 12 ? "am" : "pm"); break;
default: invalidNum = true; break;
}
break;
case 'A':
switch (n)
{
case 1: s.Append(hour < 12 ? "A" : "P"); break;
case 2: s.Append(hour < 12 ? "AM" : "PM"); break;
default: invalidNum = true; break;
}
break;
case 'f':
case 'F':
int req = 0, opt = 0; // required, optional
if (c == 'F') opt = n;
else
{
req = n;
while (i+1<len && pattern[i+1] == 'F') { ++i; ++opt; }
}
int frac = ns;
for (int x=0, tenth=100000000; x<9; ++x)
{
if (req > 0) req--;
else
{
if (frac == 0 || opt <= 0) break;
opt--;
}
s.Append(frac/tenth);
frac %= tenth;
tenth /= 10;
}
break;
case 'z':
TimeZone.Rule rule = tz.rule(year);
switch (n)
{
case 1:
int offset = rule.offset;
if (dst) offset += rule.dstOffset;
if (offset == 0) { s.Append('Z'); break; }
if (offset < 0) { s.Append('-'); offset = -offset; }
else { s.Append('+'); }
int zh = offset / 3600;
int zm = (offset % 3600) / 60;
if (zh < 10) s.Append('0'); s.Append(zh).Append(':');
if (zm < 10) s.Append('0'); s.Append(zm);
break;
case 3:
s.Append(dst ? rule.dstAbbr : rule.stdAbbr);
break;
case 4:
s.Append(tz.name());
break;
default:
invalidNum = true;
break;
}
break;
default:
if (FanInt.isAlpha(c))
throw ArgErr.make("Invalid pattern: unsupported char '" + (char)c + "'").val;
// check for symbol skip
if (i+1 < len)
{
int next = pattern[i+1];
// don't display symbol between ss.FFF if fractions is zero
if (next == 'F' && ns == 0) break;
// don't display symbol between mm:SS if secs is zero
if (next == 'S' && sec == 0 && ns == 0) break;
}
s.Append((char)c);
break;
}
// if invalid number of characters
if (invalidNum)
throw ArgErr.make("Invalid pattern: unsupported num of '" + (char)c + "' (x" + n + ")").val;
}
return s.ToString();
}