// Copyright 2016 - 2023 The excelize Authors. All rights reserved. Use of // this source code is governed by a BSD-style license that can be found in // the LICENSE file. // // Package excelize providing a set of functions that allow you to write to and // read from XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and // writing spreadsheet documents generated by Microsoft Excel™ 2007 and later. // Supports complex components by high compatibility, and provided streaming // API for generating or reading data from a worksheet with huge amounts of // data. This library needs Go version 1.16 or later. package excelize import ( "fmt" "math" "strconv" "strings" "time" "github.com/xuri/nfp" ) // languageInfo defined the required fields of localization support for number // format. type languageInfo struct { apFmt string tags []string localMonth func(t time.Time, abbr int) string } // numberFormat directly maps the number format parser runtime required // fields. type numberFormat struct { opts *Options cellType CellType section []nfp.Section t time.Time sectionIdx int date1904, isNumeric, hours, seconds, useMillisecond bool number float64 ap, localCode, result, value, valueSectionType string switchArgument, currencyString string fracHolder, fracPadding, intHolder, intPadding, expBaseLen int percent int useCommaSep, usePointer, usePositive, useScientificNotation bool } // CultureName is the type of supported language country codes types for apply // number format. type CultureName byte // This section defines the currently supported country code types enumeration // for apply number format. const ( CultureNameUnknown CultureName = iota CultureNameEnUS CultureNameZhCN ) var ( // Excel styles can reference number formats that are built-in, all of which // have an id less than 164. Note that this number format code list is under // English localization. builtInNumFmt = map[int]string{ 0: "general", 1: "0", 2: "0.00", 3: "#,##0", 4: "#,##0.00", 9: "0%", 10: "0.00%", 11: "0.00E+00", 12: "# ?/?", 13: "# ??/??", 14: "mm-dd-yy", 15: "d-mmm-yy", 16: "d-mmm", 17: "mmm-yy", 18: "h:mm AM/PM", 19: "h:mm:ss AM/PM", 20: "hh:mm", 21: "hh:mm:ss", 22: "m/d/yy hh:mm", 37: "#,##0 ;(#,##0)", 38: "#,##0 ;[red](#,##0)", 39: "#,##0.00 ;(#,##0.00)", 40: "#,##0.00 ;[red](#,##0.00)", 41: `_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)`, 42: `_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)`, 43: `_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)`, 44: `_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)`, 45: "mm:ss", 46: "[h]:mm:ss", 47: "mm:ss.0", 48: "##0.0E+0", 49: "@", } // langNumFmt defined number format code provided for language glyphs where // they occur in different language. langNumFmt = map[string]map[int]string{ "zh-tw": { 27: "[$-404]e/m/d", 28: `[$-404]e"年"m"月"d"日"`, 29: `[$-404]e"年"m"月"d"日"`, 30: "m/d/yy", 31: `yyyy"年"m"月"d"日"`, 32: `hh"時"mm"分"`, 33: `hh"時"mm"分"ss"秒"`, 34: `上午/下午 hh"時"mm"分"`, 35: `上午/下午 hh"時"mm"分"ss"秒"`, 36: "[$-404]e/m/d", 50: "[$-404]e/m/d", 51: `[$-404]e"年"m"月"d"日"`, 52: `上午/下午 hh"時"mm"分"`, 53: `上午/下午 hh"時"mm"分"ss"秒"`, 54: `[$-404]e"年"m"月"d"日"`, 55: `上午/下午 hh"時"mm"分"`, 56: `上午/下午 hh"時"mm"分"ss"秒"`, 57: "[$-404]e/m/d", 58: `[$-404]e"年"m"月"d"日"`, }, "zh-cn": { 27: `yyyy"年"m"月"`, 28: `m"月"d"日"`, 29: `m"月"d"日"`, 30: "m/d/yy", 31: `yyyy"年"m"月"d"日"`, 32: `h"时"mm"分"`, 33: `h"时"mm"分"ss"秒"`, 34: `上午/下午 h"时"mm"分"`, 35: `上午/下午 h"时"mm"分"ss"秒"`, 36: `yyyy"年"m"月"`, 50: `yyyy"年"m"月"`, 51: `m"月"d"日"`, 52: `yyyy"年"m"月"`, 53: `m"月"d"日"`, 54: `m"月"d"日"`, 55: `上午/下午 h"时"mm"分"`, 56: `上午/下午 h"时"mm"分"ss"秒"`, 57: `yyyy"年"m"月"`, 58: `m"月"d"日"`, }, "ja-jp": { 27: "[$-411]ge.m.d", 28: `[$-411]ggge"年"m"月"d"日"`, 29: `[$-411]ggge"年"m"月"d"日"`, 30: "m/d/yy", 31: `yyyy"年"m"月"d"日"`, 32: `h"時"mm"分"`, 33: `h"時"mm"分"ss"秒"`, 34: `yyyy"年"m"月"`, 35: `m"月"d"日"`, 36: "[$-411]ge.m.d", 50: "[$-411]ge.m.d", 51: `[$-411]ggge"年"m"月"d"日"`, 52: `yyyy"年"m"月"`, 53: `m"月"d"日"`, 54: `[$-411]ggge"年"m"月"d"日"`, 55: `yyyy"年"m"月"`, 56: `m"月"d"日"`, 57: "[$-411]ge.m.d", 58: `[$-411]ggge"年"m"月"d"日"`, }, "ko-kr": { 27: `yyyy"年" mm"月" dd"日"`, 28: "mm-dd", 29: "mm-dd", 30: "mm-dd-yy", 31: `yyyy"년" mm"월" dd"일"`, 32: `h"시" mm"분"`, 33: `h"시" mm"분" ss"초"`, 34: `yyyy-mm-dd`, 35: `yyyy-mm-dd`, 36: `yyyy"年" mm"月" dd"日"`, 50: `yyyy"年" mm"月" dd"日"`, 51: "mm-dd", 52: "yyyy-mm-dd", 53: "yyyy-mm-dd", 54: "mm-dd", 55: "yyyy-mm-dd", 56: "yyyy-mm-dd", 57: `yyyy"年" mm"月" dd"日"`, 58: "mm-dd", }, "th-th": { 59: "t0", 60: "t0.00", 61: "t#,##0", 62: "t#,##0.00", 67: "t0%", 68: "t0.00%", 69: "t# ?/?", 70: "t# ??/??", 71: "ว/ด/ปปปป", 72: "ว-ดดด-ปป", 73: "ว-ดดด", 74: "ดดด-ปป", 75: "ช:นน", 76: "ช:นน:ทท", 77: "ว/ด/ปปปป ช:นน", 78: "นน:ทท", 79: "[ช]:นน:ทท", 80: "นน:ทท.0", 81: "d/m/bb", }, } // currencyNumFmt defined the currency number format map. currencyNumFmt = map[int]string{ 164: `"¥"#,##0.00`, 165: "[$$-409]#,##0.00", 166: "[$$-45C]#,##0.00", 167: "[$$-1004]#,##0.00", 168: "[$$-404]#,##0.00", 169: "[$$-C09]#,##0.00", 170: "[$$-2809]#,##0.00", 171: "[$$-1009]#,##0.00", 172: "[$$-2009]#,##0.00", 173: "[$$-1409]#,##0.00", 174: "[$$-4809]#,##0.00", 175: "[$$-2C09]#,##0.00", 176: "[$$-2409]#,##0.00", 177: "[$$-1000]#,##0.00", 178: `#,##0.00\ [$$-C0C]`, 179: "[$$-475]#,##0.00", 180: "[$$-83E]#,##0.00", 181: `[$$-86B]\ #,##0.00`, 182: `[$$-340A]\ #,##0.00`, 183: "[$$-240A]#,##0.00", 184: `[$$-300A]\ #,##0.00`, 185: "[$$-440A]#,##0.00", 186: "[$$-80A]#,##0.00", 187: "[$$-500A]#,##0.00", 188: "[$$-540A]#,##0.00", 189: `[$$-380A]\ #,##0.00`, 190: "[$£-809]#,##0.00", 191: "[$£-491]#,##0.00", 192: "[$£-452]#,##0.00", 193: "[$¥-804]#,##0.00", 194: "[$¥-411]#,##0.00", 195: "[$¥-478]#,##0.00", 196: "[$¥-451]#,##0.00", 197: "[$¥-480]#,##0.00", 198: "#,##0.00\\ [$\u058F-42B]", 199: "[$\u060B-463]#,##0.00", 200: "[$\u060B-48C]#,##0.00", 201: "[$\u09F3-845]\\ #,##0.00", 202: "#,##0.00[$\u17DB-453]", 203: "[$\u20A1-140A]#,##0.00", 204: "[$\u20A6-468]\\ #,##0.00", 205: "[$\u20A6-470]\\ #,##0.00", 206: "[$\u20A9-412]#,##0.00", 207: "[$\u20AA-40D]\\ #,##0.00", 208: "#,##0.00\\ [$\u20AB-42A]", 209: "#,##0.00\\ [$\u20AC-42D]", 210: "#,##0.00\\ [$\u20AC-47E]", 211: "#,##0.00\\ [$\u20AC-403]", 212: "#,##0.00\\ [$\u20AC-483]", 213: "[$\u20AC-813]\\ #,##0.00", 214: "[$\u20AC-413]\\ #,##0.00", 215: "[$\u20AC-1809]#,##0.00", 216: "#,##0.00\\ [$\u20AC-425]", 217: "[$\u20AC-2]\\ #,##0.00", 218: "#,##0.00\\ [$\u20AC-1]", 219: "#,##0.00\\ [$\u20AC-40B]", 220: "#,##0.00\\ [$\u20AC-80C]", 221: "#,##0.00\\ [$\u20AC-40C]", 222: "#,##0.00\\ [$\u20AC-140C]", 223: "#,##0.00\\ [$\u20AC-180C]", 224: "[$\u20AC-200C]#,##0.00", 225: "#,##0.00\\ [$\u20AC-456]", 226: "#,##0.00\\ [$\u20AC-C07]", 227: "#,##0.00\\ [$\u20AC-407]", 228: "#,##0.00\\ [$\u20AC-1007]", 229: "#,##0.00\\ [$\u20AC-408]", 230: "#,##0.00\\ [$\u20AC-243B]", 231: "[$\u20AC-83C]#,##0.00", 232: "[$\u20AC-410]\\ #,##0.00", 233: "[$\u20AC-476]#,##0.00", 234: "#,##0.00\\ [$\u20AC-2C1A]", 235: "[$\u20AC-426]\\ #,##0.00", 236: "#,##0.00\\ [$\u20AC-427]", 237: "#,##0.00\\ [$\u20AC-82E]", 238: "#,##0.00\\ [$\u20AC-46E]", 239: "[$\u20AC-43A]#,##0.00", 240: "#,##0.00\\ [$\u20AC-C3B]", 241: "#,##0.00\\ [$\u20AC-482]", 242: "#,##0.00\\ [$\u20AC-816]", 243: "#,##0.00\\ [$\u20AC-301A]", 244: "#,##0.00\\ [$\u20AC-203B]", 245: "#,##0.00\\ [$\u20AC-41B]", 246: "#,##0.00\\ [$\u20AC-424]", 247: "#,##0.00\\ [$\u20AC-C0A]", 248: "#,##0.00\\ [$\u20AC-81D]", 249: "#,##0.00\\ [$\u20AC-484]", 250: "#,##0.00\\ [$\u20AC-42E]", 251: "[$\u20AC-462]\\ #,##0.00", 252: "#,##0.00\\ [$₭-454]", 253: "#,##0.00\\ [$₮-450]", 254: "[$\u20AE-C50]#,##0.00", 255: "[$\u20B1-3409]#,##0.00", 256: "[$\u20B1-464]#,##0.00", 257: "#,##0.00[$\u20B4-422]", 258: "[$\u20B8-43F]#,##0.00", 259: "[$\u20B9-460]#,##0.00", 260: "[$\u20B9-4009]\\ #,##0.00", 261: "[$\u20B9-447]\\ #,##0.00", 262: "[$\u20B9-439]\\ #,##0.00", 263: "[$\u20B9-44B]\\ #,##0.00", 264: "[$\u20B9-860]#,##0.00", 265: "[$\u20B9-457]\\ #,##0.00", 266: "[$\u20B9-458]#,##0.00", 267: "[$\u20B9-44E]\\ #,##0.00", 268: "[$\u20B9-861]#,##0.00", 269: "[$\u20B9-448]\\ #,##0.00", 270: "[$\u20B9-446]\\ #,##0.00", 271: "[$\u20B9-44F]\\ #,##0.00", 272: "[$\u20B9-459]#,##0.00", 273: "[$\u20B9-449]\\ #,##0.00", 274: "[$\u20B9-820]#,##0.00", 275: "#,##0.00\\ [$\u20BA-41F]", 276: "#,##0.00\\ [$\u20BC-42C]", 277: "#,##0.00\\ [$\u20BC-82C]", 278: "#,##0.00\\ [$\u20BD-419]", 279: "#,##0.00[$\u20BD-485]", 280: "#,##0.00\\ [$\u20BE-437]", 281: "[$B/.-180A]\\ #,##0.00", 282: "[$Br-472]#,##0.00", 283: "[$Br-477]#,##0.00", 284: "#,##0.00[$Br-473]", 285: "[$Bs-46B]\\ #,##0.00", 286: "[$Bs-400A]\\ #,##0.00", 287: "[$Bs.-200A]\\ #,##0.00", 288: "[$BWP-832]\\ #,##0.00", 289: "[$C$-4C0A]#,##0.00", 290: "[$CA$-85D]#,##0.00", 291: "[$CA$-47C]#,##0.00", 292: "[$CA$-45D]#,##0.00", 293: "[$CFA-340C]#,##0.00", 294: "[$CFA-280C]#,##0.00", 295: "#,##0.00\\ [$CFA-867]", 296: "#,##0.00\\ [$CFA-488]", 297: "#,##0.00\\ [$CHF-100C]", 298: "[$CHF-1407]\\ #,##0.00", 299: "[$CHF-807]\\ #,##0.00", 300: "[$CHF-810]\\ #,##0.00", 301: "[$CHF-417]\\ #,##0.00", 302: "[$CLP-47A]\\ #,##0.00", 303: "[$CN¥-850]#,##0.00", 304: "#,##0.00\\ [$DZD-85F]", 305: "[$FCFA-2C0C]#,##0.00", 306: "#,##0.00\\ [$Ft-40E]", 307: "[$G-3C0C]#,##0.00", 308: "[$Gs.-3C0A]\\ #,##0.00", 309: "[$GTQ-486]#,##0.00", 310: "[$HK$-C04]#,##0.00", 311: "[$HK$-3C09]#,##0.00", 312: "#,##0.00\\ [$HRK-41A]", 313: "[$IDR-3809]#,##0.00", 314: "[$IQD-492]#,##0.00", 315: "#,##0.00\\ [$ISK-40F]", 316: "[$K-455]#,##0.00", 317: "#,##0.00\\ [$K\u010D-405]", 318: "#,##0.00\\ [$KM-141A]", 319: "#,##0.00\\ [$KM-101A]", 320: "#,##0.00\\ [$KM-181A]", 321: "[$kr-438]\\ #,##0.00", 322: "[$kr-43B]\\ #,##0.00", 323: "#,##0.00\\ [$kr-83B]", 324: "[$kr-414]\\ #,##0.00", 325: "[$kr-814]\\ #,##0.00", 326: "#,##0.00\\ [$kr-41D]", 327: "[$kr.-406]\\ #,##0.00", 328: "[$kr.-46F]\\ #,##0.00", 329: "[$Ksh-441]#,##0.00", 330: "[$L-818]#,##0.00", 331: "[$L-819]#,##0.00", 332: "[$L-480A]\\ #,##0.00", 333: "#,##0.00\\ [$Lek\u00EB-41C]", 334: "[$MAD-45F]#,##0.00", 335: "[$MAD-380C]#,##0.00", 336: "#,##0.00\\ [$MAD-105F]", 337: "[$MOP$-1404]#,##0.00", 338: "#,##0.00\\ [$MVR-465]_-", 339: "#,##0.00[$Nfk-873]", 340: "[$NGN-466]#,##0.00", 341: "[$NGN-467]#,##0.00", 342: "[$NGN-469]#,##0.00", 343: "[$NGN-471]#,##0.00", 344: "[$NOK-103B]\\ #,##0.00", 345: "[$NOK-183B]\\ #,##0.00", 346: "[$NZ$-481]#,##0.00", 347: "[$PKR-859]\\ #,##0.00", 348: "[$PYG-474]#,##0.00", 349: "[$Q-100A]#,##0.00", 350: "[$R-436]\\ #,##0.00", 351: "[$R-1C09]\\ #,##0.00", 352: "[$R-435]\\ #,##0.00", 353: "[$R$-416]\\ #,##0.00", 354: "[$RD$-1C0A]#,##0.00", 355: "#,##0.00\\ [$RF-487]", 356: "[$RM-4409]#,##0.00", 357: "[$RM-43E]#,##0.00", 358: "#,##0.00\\ [$RON-418]", 359: "[$Rp-421]#,##0.00", 360: "[$Rs-420]#,##0.00_-", 361: "[$Rs.-849]\\ #,##0.00", 362: "#,##0.00\\ [$RSD-81A]", 363: "#,##0.00\\ [$RSD-C1A]", 364: "#,##0.00\\ [$RUB-46D]", 365: "#,##0.00\\ [$RUB-444]", 366: "[$S/.-C6B]\\ #,##0.00", 367: "[$S/.-280A]\\ #,##0.00", 368: "#,##0.00\\ [$SEK-143B]", 369: "#,##0.00\\ [$SEK-1C3B]", 370: "#,##0.00\\ [$so\u02BBm-443]", 371: "#,##0.00\\ [$so\u02BBm-843]", 372: "#,##0.00\\ [$SYP-45A]", 373: "[$THB-41E]#,##0.00", 374: "#,##0.00[$TMT-442]", 375: "[$US$-3009]#,##0.00", 376: "[$ZAR-46C]\\ #,##0.00", 377: "[$ZAR-430]#,##0.00", 378: "[$ZAR-431]#,##0.00", 379: "[$ZAR-432]\\ #,##0.00", 380: "[$ZAR-433]#,##0.00", 381: "[$ZAR-434]\\ #,##0.00", 382: "#,##0.00\\ [$z\u0142-415]", 383: "#,##0.00\\ [$\u0434\u0435\u043D-42F]", 384: "#,##0.00\\ [$КМ-201A]", 385: "#,##0.00\\ [$КМ-1C1A]", 386: "#,##0.00\\ [$\u043B\u0432.-402]", 387: "#,##0.00\\ [$р.-423]", 388: "#,##0.00\\ [$\u0441\u043E\u043C-440]", 389: "#,##0.00\\ [$\u0441\u043E\u043C-428]", 390: "[$\u062C.\u0645.-C01]\\ #,##0.00_-", 391: "[$\u062F.\u0623.-2C01]\\ #,##0.00_-", 392: "[$\u062F.\u0625.-3801]\\ #,##0.00_-", 393: "[$\u062F.\u0628.-3C01]\\ #,##0.00_-", 394: "[$\u062F.\u062A.-1C01]\\ #,##0.00_-", 395: "[$\u062F.\u062C.-1401]\\ #,##0.00_-", 396: "[$\u062F.\u0639.-801]\\ #,##0.00_-", 397: "[$\u062F.\u0643.-3401]\\ #,##0.00_-", 398: "[$\u062F.\u0644.-1001]#,##0.00_-", 399: "[$\u062F.\u0645.-1801]\\ #,##0.00_-", 400: "[$\u0631-846]\\ #,##0.00", 401: "[$\u0631.\u0633.-401]\\ #,##0.00_-", 402: "[$\u0631.\u0639.-2001]\\ #,##0.00_-", 403: "[$\u0631.\u0642.-4001]\\ #,##0.00_-", 404: "[$\u0631.\u064A.-2401]\\ #,##0.00_-", 405: "[$\u0631\u06CC\u0627\u0644-429]#,##0.00_-", 406: "[$\u0644.\u0633.-2801]\\ #,##0.00_-", 407: "[$\u0644.\u0644.-3001]\\ #,##0.00_-", 408: "[$\u1265\u122D-45E]#,##0.00", 409: "[$\u0930\u0942-461]#,##0.00", 410: "[$\u0DBB\u0DD4.-45B]\\ #,##0.00", 411: "[$ADP]\\ #,##0.00", 412: "[$AED]\\ #,##0.00", 413: "[$AFA]\\ #,##0.00", 414: "[$AFN]\\ #,##0.00", 415: "[$ALL]\\ #,##0.00", 416: "[$AMD]\\ #,##0.00", 417: "[$ANG]\\ #,##0.00", 418: "[$AOA]\\ #,##0.00", 419: "[$ARS]\\ #,##0.00", 420: "[$ATS]\\ #,##0.00", 421: "[$AUD]\\ #,##0.00", 422: "[$AWG]\\ #,##0.00", 423: "[$AZM]\\ #,##0.00", 424: "[$AZN]\\ #,##0.00", 425: "[$BAM]\\ #,##0.00", 426: "[$BBD]\\ #,##0.00", 427: "[$BDT]\\ #,##0.00", 428: "[$BEF]\\ #,##0.00", 429: "[$BGL]\\ #,##0.00", 430: "[$BGN]\\ #,##0.00", 431: "[$BHD]\\ #,##0.00", 432: "[$BIF]\\ #,##0.00", 433: "[$BMD]\\ #,##0.00", 434: "[$BND]\\ #,##0.00", 435: "[$BOB]\\ #,##0.00", 436: "[$BOV]\\ #,##0.00", 437: "[$BRL]\\ #,##0.00", 438: "[$BSD]\\ #,##0.00", 439: "[$BTN]\\ #,##0.00", 440: "[$BWP]\\ #,##0.00", 441: "[$BYR]\\ #,##0.00", 442: "[$BZD]\\ #,##0.00", 443: "[$CAD]\\ #,##0.00", 444: "[$CDF]\\ #,##0.00", 445: "[$CHE]\\ #,##0.00", 446: "[$CHF]\\ #,##0.00", 447: "[$CHW]\\ #,##0.00", 448: "[$CLF]\\ #,##0.00", 449: "[$CLP]\\ #,##0.00", 450: "[$CNY]\\ #,##0.00", 451: "[$COP]\\ #,##0.00", 452: "[$COU]\\ #,##0.00", 453: "[$CRC]\\ #,##0.00", 454: "[$CSD]\\ #,##0.00", 455: "[$CUC]\\ #,##0.00", 456: "[$CVE]\\ #,##0.00", 457: "[$CYP]\\ #,##0.00", 458: "[$CZK]\\ #,##0.00", 459: "[$DEM]\\ #,##0.00", 460: "[$DJF]\\ #,##0.00", 461: "[$DKK]\\ #,##0.00", 462: "[$DOP]\\ #,##0.00", 463: "[$DZD]\\ #,##0.00", 464: "[$ECS]\\ #,##0.00", 465: "[$ECV]\\ #,##0.00", 466: "[$EEK]\\ #,##0.00", 467: "[$EGP]\\ #,##0.00", 468: "[$ERN]\\ #,##0.00", 469: "[$ESP]\\ #,##0.00", 470: "[$ETB]\\ #,##0.00", 471: "[$EUR]\\ #,##0.00", 472: "[$FIM]\\ #,##0.00", 473: "[$FJD]\\ #,##0.00", 474: "[$FKP]\\ #,##0.00", 475: "[$FRF]\\ #,##0.00", 476: "[$GBP]\\ #,##0.00", 477: "[$GEL]\\ #,##0.00", 478: "[$GHC]\\ #,##0.00", 479: "[$GHS]\\ #,##0.00", 480: "[$GIP]\\ #,##0.00", 481: "[$GMD]\\ #,##0.00", 482: "[$GNF]\\ #,##0.00", 483: "[$GRD]\\ #,##0.00", 484: "[$GTQ]\\ #,##0.00", 485: "[$GYD]\\ #,##0.00", 486: "[$HKD]\\ #,##0.00", 487: "[$HNL]\\ #,##0.00", 488: "[$HRK]\\ #,##0.00", 489: "[$HTG]\\ #,##0.00", 490: "[$HUF]\\ #,##0.00", 491: "[$IDR]\\ #,##0.00", 492: "[$IEP]\\ #,##0.00", 493: "[$ILS]\\ #,##0.00", 494: "[$INR]\\ #,##0.00", 495: "[$IQD]\\ #,##0.00", 496: "[$IRR]\\ #,##0.00", 497: "[$ISK]\\ #,##0.00", 498: "[$ITL]\\ #,##0.00", 499: "[$JMD]\\ #,##0.00", 500: "[$JOD]\\ #,##0.00", 501: "[$JPY]\\ #,##0.00", 502: "[$KAF]\\ #,##0.00", 503: "[$KES]\\ #,##0.00", 504: "[$KGS]\\ #,##0.00", 505: "[$KHR]\\ #,##0.00", 506: "[$KMF]\\ #,##0.00", 507: "[$KPW]\\ #,##0.00", 508: "[$KRW]\\ #,##0.00", 509: "[$KWD]\\ #,##0.00", 510: "[$KYD]\\ #,##0.00", 511: "[$KZT]\\ #,##0.00", 512: "[$LAK]\\ #,##0.00", 513: "[$LBP]\\ #,##0.00", 514: "[$LKR]\\ #,##0.00", 515: "[$LRD]\\ #,##0.00", 516: "[$LSL]\\ #,##0.00", 517: "[$LTL]\\ #,##0.00", 518: "[$LUF]\\ #,##0.00", 519: "[$LVL]\\ #,##0.00", 520: "[$LYD]\\ #,##0.00", 521: "[$MAD]\\ #,##0.00", 522: "[$MDL]\\ #,##0.00", 523: "[$MGA]\\ #,##0.00", 524: "[$MGF]\\ #,##0.00", 525: "[$MKD]\\ #,##0.00", 526: "[$MMK]\\ #,##0.00", 527: "[$MNT]\\ #,##0.00", 528: "[$MOP]\\ #,##0.00", 529: "[$MRO]\\ #,##0.00", 530: "[$MTL]\\ #,##0.00", 531: "[$MUR]\\ #,##0.00", 532: "[$MVR]\\ #,##0.00", 533: "[$MWK]\\ #,##0.00", 534: "[$MXN]\\ #,##0.00", 535: "[$MXV]\\ #,##0.00", 536: "[$MYR]\\ #,##0.00", 537: "[$MZM]\\ #,##0.00", 538: "[$MZN]\\ #,##0.00", 539: "[$NAD]\\ #,##0.00", 540: "[$NGN]\\ #,##0.00", 541: "[$NIO]\\ #,##0.00", 542: "[$NLG]\\ #,##0.00", 543: "[$NOK]\\ #,##0.00", 544: "[$NPR]\\ #,##0.00", 545: "[$NTD]\\ #,##0.00", 546: "[$NZD]\\ #,##0.00", 547: "[$OMR]\\ #,##0.00", 548: "[$PAB]\\ #,##0.00", 549: "[$PEN]\\ #,##0.00", 550: "[$PGK]\\ #,##0.00", 551: "[$PHP]\\ #,##0.00", 552: "[$PKR]\\ #,##0.00", 553: "[$PLN]\\ #,##0.00", 554: "[$PTE]\\ #,##0.00", 555: "[$PYG]\\ #,##0.00", 556: "[$QAR]\\ #,##0.00", 557: "[$ROL]\\ #,##0.00", 558: "[$RON]\\ #,##0.00", 559: "[$RSD]\\ #,##0.00", 560: "[$RUB]\\ #,##0.00", 561: "[$RUR]\\ #,##0.00", 562: "[$RWF]\\ #,##0.00", 563: "[$SAR]\\ #,##0.00", 564: "[$SBD]\\ #,##0.00", 565: "[$SCR]\\ #,##0.00", 566: "[$SDD]\\ #,##0.00", 567: "[$SDG]\\ #,##0.00", 568: "[$SDP]\\ #,##0.00", 569: "[$SEK]\\ #,##0.00", 570: "[$SGD]\\ #,##0.00", 571: "[$SHP]\\ #,##0.00", 572: "[$SIT]\\ #,##0.00", 573: "[$SKK]\\ #,##0.00", 574: "[$SLL]\\ #,##0.00", 575: "[$SOS]\\ #,##0.00", 576: "[$SPL]\\ #,##0.00", 577: "[$SRD]\\ #,##0.00", 578: "[$SRG]\\ #,##0.00", 579: "[$STD]\\ #,##0.00", 580: "[$SVC]\\ #,##0.00", 581: "[$SYP]\\ #,##0.00", 582: "[$SZL]\\ #,##0.00", 583: "[$THB]\\ #,##0.00", 584: "[$TJR]\\ #,##0.00", 585: "[$TJS]\\ #,##0.00", 586: "[$TMM]\\ #,##0.00", 587: "[$TMT]\\ #,##0.00", 588: "[$TND]\\ #,##0.00", 589: "[$TOP]\\ #,##0.00", 590: "[$TRL]\\ #,##0.00", 591: "[$TRY]\\ #,##0.00", 592: "[$TTD]\\ #,##0.00", 593: "[$TWD]\\ #,##0.00", 594: "[$TZS]\\ #,##0.00", 595: "[$UAH]\\ #,##0.00", 596: "[$UGX]\\ #,##0.00", 597: "[$USD]\\ #,##0.00", 598: "[$USN]\\ #,##0.00", 599: "[$USS]\\ #,##0.00", 600: "[$UYI]\\ #,##0.00", 601: "[$UYU]\\ #,##0.00", 602: "[$UZS]\\ #,##0.00", 603: "[$VEB]\\ #,##0.00", 604: "[$VEF]\\ #,##0.00", 605: "[$VND]\\ #,##0.00", 606: "[$VUV]\\ #,##0.00", 607: "[$WST]\\ #,##0.00", 608: "[$XAF]\\ #,##0.00", 609: "[$XAG]\\ #,##0.00", 610: "[$XAU]\\ #,##0.00", 611: "[$XB5]\\ #,##0.00", 612: "[$XBA]\\ #,##0.00", 613: "[$XBB]\\ #,##0.00", 614: "[$XBC]\\ #,##0.00", 615: "[$XBD]\\ #,##0.00", 616: "[$XCD]\\ #,##0.00", 617: "[$XDR]\\ #,##0.00", 618: "[$XFO]\\ #,##0.00", 619: "[$XFU]\\ #,##0.00", 620: "[$XOF]\\ #,##0.00", 621: "[$XPD]\\ #,##0.00", 622: "[$XPF]\\ #,##0.00", 623: "[$XPT]\\ #,##0.00", 624: "[$XTS]\\ #,##0.00", 625: "[$XXX]\\ #,##0.00", 626: "[$YER]\\ #,##0.00", 627: "[$YUM]\\ #,##0.00", 628: "[$ZAR]\\ #,##0.00", 629: "[$ZMK]\\ #,##0.00", 630: "[$ZMW]\\ #,##0.00", 631: "[$ZWD]\\ #,##0.00", 632: "[$ZWL]\\ #,##0.00", 633: "[$ZWN]\\ #,##0.00", 634: "[$ZWR]\\ #,##0.00", } // supportedTokenTypes list the supported number format token types currently. supportedTokenTypes = []string{ nfp.TokenSubTypeCurrencyString, nfp.TokenSubTypeLanguageInfo, nfp.TokenTypeColor, nfp.TokenTypeCurrencyLanguage, nfp.TokenTypeDateTimes, nfp.TokenTypeDecimalPoint, nfp.TokenTypeElapsedDateTimes, nfp.TokenTypeExponential, nfp.TokenTypeGeneral, nfp.TokenTypeHashPlaceHolder, nfp.TokenTypeLiteral, nfp.TokenTypePercent, nfp.TokenTypeSwitchArgument, nfp.TokenTypeTextPlaceHolder, nfp.TokenTypeThousandsSeparator, nfp.TokenTypeZeroPlaceHolder, } // supportedNumberTokenTypes list the supported number token types. supportedNumberTokenTypes = []string{ nfp.TokenTypeExponential, nfp.TokenTypeHashPlaceHolder, nfp.TokenTypePercent, nfp.TokenTypeZeroPlaceHolder, } // supportedDateTimeTokenTypes list the supported date and time token types. supportedDateTimeTokenTypes = []string{ nfp.TokenTypeDateTimes, nfp.TokenTypeElapsedDateTimes, } // supportedLanguageInfo directly maps the supported language ID and tags. supportedLanguageInfo = map[string]languageInfo{ "36": {tags: []string{"af"}, localMonth: localMonthsNameAfrikaans, apFmt: apFmtAfrikaans}, "445": {tags: []string{"bn-IN"}, localMonth: localMonthsNameBangla, apFmt: nfp.AmPm[0]}, "4": {tags: []string{"zh-Hans"}, localMonth: localMonthsNameChinese1, apFmt: nfp.AmPm[2]}, "7804": {tags: []string{"zh"}, localMonth: localMonthsNameChinese1, apFmt: nfp.AmPm[2]}, "804": {tags: []string{"zh-CN"}, localMonth: localMonthsNameChinese1, apFmt: nfp.AmPm[2]}, "1004": {tags: []string{"zh-SG"}, localMonth: localMonthsNameChinese2, apFmt: nfp.AmPm[2]}, "7C04": {tags: []string{"zh-Hant"}, localMonth: localMonthsNameChinese3, apFmt: nfp.AmPm[2]}, "C04": {tags: []string{"zh-HK"}, localMonth: localMonthsNameChinese2, apFmt: nfp.AmPm[2]}, "1404": {tags: []string{"zh-MO"}, localMonth: localMonthsNameChinese3, apFmt: nfp.AmPm[2]}, "404": {tags: []string{"zh-TW"}, localMonth: localMonthsNameChinese3, apFmt: nfp.AmPm[2]}, "9": {tags: []string{"en"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "1000": {tags: []string{ "aa", "aa-DJ", "aa-ER", "aa-ER", "aa-NA", "agq", "agq-CM", "ak", "ak-GH", "sq-ML", "gsw-LI", "gsw-CH", "ar-TD", "ar-KM", "ar-DJ", "ar-ER", "ar-IL", "ar-MR", "ar-PS", "ar-SO", "ar-SS", "ar-SD", "ar-001", "ast", "ast-ES", "asa", "asa-TZ", "ksf", "ksf-CM", "bm", "bm-Latn-ML", "bas", "bas-CM", "bem", "bem-ZM", "bez", "bez-TZ", "byn", "byn-ER", "brx", "brx-IN", "ca-AD", "ca-FR", "ca-IT", "ceb", "ceb-Latn", "ceb-Latn-PH", "tzm-Latn-MA", "ccp", "ccp-Cakm", "ccp-Cakm-BD", "ccp-Cakm-IN", "ce-RU", "cgg", "cgg-UG", "cu-RU", "swc", "swc-CD", "kw", "ke-GB", "da-GL", "dua", "dua-CM", "nl-AW", "nl-BQ", "nl-CW", "nl-SX", "nl-SR", "dz", "ebu", "ebu-KE", "en-AS", "en-AI", "en-AG", "en-AT", "en-BS", "en-BB", "en-BE", "en-BM", "en-BW", "en-IO", "en-VG", "en-BI", "en-CM", "en-KY", "en-CX", "en-CC", "en-CK", "en-CY", "en-DK", "en-DM", "en-ER", "en-150", "en-FK", "en-FI", "en-FJ", "en-GM", "en-DE", "en-GH", "en-GI", "en-GD", "en-GU", "en-GG", "en-GY", "en-IM", "en-IL", "en-JE", "en-KE", "en-KI", "en-LS", "en-LR", "en-MO", "en-MG", "en-MW", "en-MT", "en-MH", "en-MU", "en-FM", "en-MS", "en-NA", "en-NR", "en-NL", "en-NG", "en-NU", "en-NF", "en-MP", "en-PK", "en-PW", "en-PG", "en-PN", "en-PR", "en-RW", "en-KN", "en-LC", "en-VC", "en-WS", "en-SC", "en-SL", "en-SX", "en-SI", "en-SB", "en-SS", "en-SH", "en-SD", "en-SZ", "en-SE", "en-CH", "en-TZ", "en-TK", "en-TO", "en-TC", "en-TV", "en-UG", "en-UM", "en-VI", "en-VU", "en-001", "en-ZM", "eo", "eo-001", "ee", "ee-GH", "ee-TG", "ewo", "ewo-CM", "fo-DK", "fr-DZ", "fr-BJ", "fr-BF", "fr-BI", "fr-CF", "fr-TD", "fr-KM", "fr-CG", "fr-DJ", "fr-GQ", "fr-GF", "fr-PF", "fr-GA", "fr-GP", "fr-GN", "fr-MG", "fr-MQ", "fr-MR", "fr-MU", "fr-YT", "fr-NC", "fr-NE", "fr-RW", "fr-BL", "fr-MF", "fr-PM", "fr-SC", "fr-SY", "fr-TG", "fr-TN", "fr-VU", "fr-WF", "fur", "fur-IT", "ff-Latn-BF", "ff-CM", "ff-Latn-CM", "ff-Latn-GM", "ff-Latn-GH", "ff-GN", "ff-Latn-GN", "ff-Latn-GW", "ff-Latn-LR", "ff-MR", "ff-Latn-MR", "ff-Latn-NE", "ff-Latn-SL", "lg", "lg-UG", "de-BE", "de-IT", "el-CY", "guz", "guz-KE", "ha-Latn-GH", "ha-Latn-NG", "ia-FR", "ia-001", "it-SM", "it-VA", "jv", "jv-Latn", "jv-Latn-ID", "dyo", "dyo-SN", "kea", "kea-CV", "kab", "kab-DZ", "kkj", "kkj-CM", "kln", "kln-KE", "kam", "kam-KE", "ks-Arab-IN", "ki", "ki-KE", "sw-TZ", "sw-UG", "ko-KP", "khq", "khq-ML", "ses", "ses-ML", "nmg", "nmq-CM", "ku-Arab-IR", "lkt", "lkt-US", "lag", "lag-TZ", "ln", "ln-AO", "ln-CF", "ln-CD", "nds", "nds-DE", "nds-NL", "lu", "lu-CD", "luo", "luo", "luo-KE", "luy", "luy-KE", "jmc", "jmc-TZ", "mgh", "mgh-MZ", "kde", "kde-TZ", "mg", "mg-MG", "gv", "gv-IM", "mas", "mas-KE", "mas-TZ", "mas-IR", "mer", "mer-KE", "mgo", "mgo-CM", "mfe", "mfe-MU", "mua", "mua-CM", "nqo", "nqo-GN", "nqa", "naq-NA", "nnh", "nnh-CM", "jgo", "jgo-CM", "lrc-IQ", "lrc-IR", "nd", "nd-ZW", "nb-SJ", "nus", "nus-SD", "nus-SS", "nyn", "nyn-UG", "om-KE", "os", "os-GE", "os-RU", "ps-PK", "fa-AF", "pt-AO", "pt-CV", "pt-GQ", "pt-GW", "pt-LU", "pt-MO", "pt-MZ", "pt-ST", "pt-CH", "pt-TL", "prg-001", "ksh", "ksh-DE", "rof", "rof-TZ", "rn", "rn-BI", "ru-BY", "ru-KZ", "ru-KG", "ru-UA", "rwk", "rwk-TZ", "ssy", "ssy-ER", "saq", "saq-KE", "sg", "sq-CF", "sbp", "sbp-TZ", "seh", "seh-MZ", "ksb", "ksb-TZ", "sn", "sn-Latn", "sn-Latn-ZW", "xog", "xog-UG", "so-DJ", "so-ET", "so-KE", "nr", "nr-ZA", "st-LS", "es-BZ", "es-BR", "es-PH", "zgh", "zgh-Tfng-MA", "zgh-Tfng", "ss", "ss-ZA", "ss-SZ", "sv-AX", "shi", "shi-Tfng", "shi-Tfng-MA", "shi-Latn", "shi-Latn-MA", "dav", "dav-KE", "ta-MY", "ta-SG", "twq", "twq-NE", "teo", "teo-KE", "teo-UG", "bo-IN", "tig", "tig-ER", "to", "to-TO", "tr-CY", "uz-Arab", "us-Arab-AF", "vai", "vai-Vaii", "vai-Vaii-LR", "vai-Latn-LR", "vai-Latn", "vo", "vo-001", "vun", "vun-TZ", "wae", "wae-CH", "wal", "wae-ET", "yav", "yav-CM", "yo-BJ", "dje", "dje-NE", }, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "C09": {tags: []string{"en-AU"}, localMonth: localMonthsNameEnglish, apFmt: strings.ToLower(nfp.AmPm[0])}, "2829": {tags: []string{"en-BZ"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "1009": {tags: []string{"en-CA"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "2409": {tags: []string{"en-029"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "3C09": {tags: []string{"en-HK"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "4009": {tags: []string{"en-IN"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "1809": {tags: []string{"en-IE"}, localMonth: localMonthsNameEnglish, apFmt: strings.ToLower(nfp.AmPm[0])}, "2009": {tags: []string{"en-JM"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "4409": {tags: []string{"en-MY"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "1409": {tags: []string{"en-NZ"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "3409": {tags: []string{"en-PH"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "4809": {tags: []string{"en-SG"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "1C09": {tags: []string{"en-ZA"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "2C09": {tags: []string{"en-TT"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "4C09": {tags: []string{"en-AE"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "809": {tags: []string{"en-GB"}, localMonth: localMonthsNameEnglish, apFmt: strings.ToLower(nfp.AmPm[0])}, "409": {tags: []string{"en-US"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "3009": {tags: []string{"en-ZW"}, localMonth: localMonthsNameEnglish, apFmt: nfp.AmPm[0]}, "C": {tags: []string{"fr"}, localMonth: localMonthsNameFrench, apFmt: nfp.AmPm[0]}, "7": {tags: []string{"de"}, localMonth: localMonthsNameGerman, apFmt: nfp.AmPm[0]}, "C07": {tags: []string{"de-AT"}, localMonth: localMonthsNameAustria, apFmt: nfp.AmPm[0]}, "407": {tags: []string{"de-DE"}, localMonth: localMonthsNameGerman, apFmt: nfp.AmPm[0]}, "3C": {tags: []string{"ga"}, localMonth: localMonthsNameIrish, apFmt: apFmtIrish}, "83C": {tags: []string{"ga-IE"}, localMonth: localMonthsNameIrish, apFmt: apFmtIrish}, "10": {tags: []string{"it"}, localMonth: localMonthsNameItalian, apFmt: nfp.AmPm[0]}, "11": {tags: []string{"ja"}, localMonth: localMonthsNameChinese3, apFmt: apFmtJapanese}, "411": {tags: []string{"ja-JP"}, localMonth: localMonthsNameChinese3, apFmt: apFmtJapanese}, "12": {tags: []string{"ko"}, localMonth: localMonthsNameKorean, apFmt: apFmtKorean}, "412": {tags: []string{"ko-KR"}, localMonth: localMonthsNameKorean, apFmt: apFmtKorean}, "7C50": {tags: []string{"mn-Mong"}, localMonth: localMonthsNameTraditionalMongolian, apFmt: nfp.AmPm[0]}, "850": {tags: []string{"mn-Mong-CN"}, localMonth: localMonthsNameTraditionalMongolian, apFmt: nfp.AmPm[0]}, "C50": {tags: []string{"mn-Mong-MN"}, localMonth: localMonthsNameTraditionalMongolian, apFmt: nfp.AmPm[0]}, "19": {tags: []string{"ru"}, localMonth: localMonthsNameRussian, apFmt: nfp.AmPm[0]}, "819": {tags: []string{"ru-MD"}, localMonth: localMonthsNameRussian, apFmt: nfp.AmPm[0]}, "419": {tags: []string{"ru-RU"}, localMonth: localMonthsNameRussian, apFmt: nfp.AmPm[0]}, "A": {tags: []string{"es"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "2C0A": {tags: []string{"es-AR"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "200A": {tags: []string{"es-VE"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "400A": {tags: []string{"es-BO"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "340A": {tags: []string{"es-CL"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "240A": {tags: []string{"es-CO"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "140A": {tags: []string{"es-CR"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "5C0A": {tags: []string{"es-CU"}, localMonth: localMonthsNameSpanish, apFmt: apFmtCuba}, "1C0A": {tags: []string{"es-DO"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "300A": {tags: []string{"es-EC"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "440A": {tags: []string{"es-SV"}, localMonth: localMonthsNameSpanish, apFmt: apFmtSpanish}, "1E": {tags: []string{"th"}, localMonth: localMonthsNameThai, apFmt: nfp.AmPm[0]}, "41E": {tags: []string{"th-TH"}, localMonth: localMonthsNameThai, apFmt: nfp.AmPm[0]}, "51": {tags: []string{"bo"}, localMonth: localMonthsNameTibetan, apFmt: apFmtTibetan}, "451": {tags: []string{"bo-CN"}, localMonth: localMonthsNameTibetan, apFmt: apFmtTibetan}, "1F": {tags: []string{"tr"}, localMonth: localMonthsNameTurkish, apFmt: apFmtTurkish}, "41F": {tags: []string{"tr-TR"}, localMonth: localMonthsNameTurkish, apFmt: apFmtTurkish}, "52": {tags: []string{"cy"}, localMonth: localMonthsNameWelsh, apFmt: apFmtWelsh}, "452": {tags: []string{"cy-GB"}, localMonth: localMonthsNameWelsh, apFmt: apFmtWelsh}, "2A": {tags: []string{"vi"}, localMonth: localMonthsNameVietnamese, apFmt: apFmtVietnamese}, "42A": {tags: []string{"vi-VN"}, localMonth: localMonthsNameVietnamese, apFmt: apFmtVietnamese}, "88": {tags: []string{"wo"}, localMonth: localMonthsNameWolof, apFmt: apFmtWolof}, "488": {tags: []string{"wo-SN"}, localMonth: localMonthsNameWolof, apFmt: apFmtWolof}, "34": {tags: []string{"xh"}, localMonth: localMonthsNameXhosa, apFmt: nfp.AmPm[0]}, "434": {tags: []string{"xh-ZA"}, localMonth: localMonthsNameXhosa, apFmt: nfp.AmPm[0]}, "78": {tags: []string{"ii"}, localMonth: localMonthsNameYi, apFmt: apFmtYi}, "478": {tags: []string{"ii-CN"}, localMonth: localMonthsNameYi, apFmt: apFmtYi}, "35": {tags: []string{"zu"}, localMonth: localMonthsNameZulu, apFmt: nfp.AmPm[0]}, "435": {tags: []string{"zu-ZA"}, localMonth: localMonthsNameZulu, apFmt: nfp.AmPm[0]}, } // monthNamesBangla list the month names in the Bangla. monthNamesBangla = []string{ "\u099C\u09BE\u09A8\u09C1\u09AF\u09BC\u09BE\u09B0\u09C0", "\u09AB\u09C7\u09AC\u09CD\u09B0\u09C1\u09AF\u09BC\u09BE\u09B0\u09C0", "\u09AE\u09BE\u09B0\u09CD\u099A", "\u098F\u09AA\u09CD\u09B0\u09BF\u09B2", "\u09AE\u09C7", "\u099C\u09C1\u09A8", "\u099C\u09C1\u09B2\u09BE\u0987", "\u0986\u0997\u09B8\u09CD\u099F", "\u09B8\u09C7\u09AA\u09CD\u099F\u09C7\u09AE\u09CD\u09AC\u09B0", "\u0985\u0995\u09CD\u099F\u09CB\u09AC\u09B0", "\u09A8\u09AD\u09C7\u09AE\u09CD\u09AC\u09B0", "\u09A1\u09BF\u09B8\u09C7\u09AE\u09CD\u09AC\u09B0", } // monthNamesAfrikaans list the month names in the Afrikaans. monthNamesAfrikaans = []string{"Januarie", "Februarie", "Maart", "April", "Mei", "Junie", "Julie", "Augustus", "September", "Oktober", "November", "Desember"} // monthNamesAfrikaansAbbr lists the month name abbreviations in Afrikaans monthNamesAfrikaansAbbr = []string{"Jan.", "Feb.", "Maa.", "Apr.", "Mei", "Jun.", "Jul.", "Aug.", "Sep.", "Okt.", "Nov.", "Des."} // monthNamesChinese list the month names in the Chinese. monthNamesChinese = []string{"一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"} // monthNamesChineseAbbr1 list the month number and character abbreviation in Chinese monthNamesChineseAbbrPlus = []string{"0月", "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月"} // monthNamesChinesePlus list the month names in Chinese plus the character 月 monthNamesChinesePlus = []string{"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"} // monthNamesKoreanAbbrPlus lists out the month number plus 월 for the Korean language monthNamesKoreanAbbrPlus = []string{"0월", "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월"} // monthNamesTradMongolian lists the month number for use with traditional Mongolian monthNamesTradMongolian = []string{"M01", "M02", "M03", "M04", "M05", "M06", "M07", "M08", "M09", "M10", "M11", "M12"} // monthNamesFrench list the month names in the French. monthNamesFrench = []string{"janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"} // monthNamesFrenchAbbr lists the month name abbreviations in French monthNamesFrenchAbbr = []string{"janv.", "févr.", "mars", "avri.", "mai", "juin", "juil.", "août", "sept.", "octo.", "nove.", "déce."} // monthNamesGerman list the month names in the German. monthNamesGerman = []string{"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"} // monthNamesGermanAbbr list the month abbreviations in German monthNamesGermanAbbr = []string{"Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"} // monthNamesAustria list the month names in the Austria. monthNamesAustria = []string{"Jänner", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"} // monthNamesAustriaAbbr list the month name abbreviations in Austrian monthNamesAustriaAbbr = []string{"Jän", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"} // monthNamesIrish list the month names in the Irish. monthNamesIrish = []string{"Eanáir", "Feabhra", "Márta", "Aibreán", "Bealtaine", "Meitheamh", "Iúil", "Lúnasa", "Meán Fómhair", "Deireadh Fómhair", "Samhain", "Nollaig"} // monthNamesIrishAbbr lists the month abbreviations in Irish monthNamesIrishAbbr = []string{"Ean", "Feabh", "Márta", "Aib", "Beal", "Meith", "Iúil", "Lún", "MFómh", "DFómh", "Samh", "Noll"} // monthNamesItalian list the month names in the Italian. monthNamesItalian = []string{"gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"} // monthNamesItalianAbbr list the month name abbreviations in Italian monthNamesItalianAbbr = []string{"gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic"} // monthNamesRussian list the month names in the Russian. monthNamesRussian = []string{"январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"} // monthNamesRussianAbbr list the month abbreviations for Russian. monthNamesRussianAbbr = []string{"янв.", "фев.", "март", "апр.", "май", "июнь", "июль", "авг.", "сен.", "окт.", "ноя.", "дек."} // monthNamesSpanish list the month names in the Spanish. monthNamesSpanish = []string{"enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"} // monthNamesSpanishAbbr list the month abbreviations in Spanish monthNamesSpanishAbbr = []string{"ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"} // monthNamesThai list the month names in the Thai. monthNamesThai = []string{ "\u0e21\u0e01\u0e23\u0e32\u0e04\u0e21", "\u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c", "\u0e21\u0e35\u0e19\u0e32\u0e04\u0e21", "\u0e40\u0e21\u0e29\u0e32\u0e22\u0e19", "\u0e1e\u0e24\u0e29\u0e20\u0e32\u0e04\u0e21", "\u0e21\u0e34\u0e16\u0e38\u0e19\u0e32\u0e22\u0e19", "\u0e01\u0e23\u0e01\u0e0e\u0e32\u0e04\u0e21", "\u0e2a\u0e34\u0e07\u0e2b\u0e32\u0e04\u0e21", "\u0e01\u0e31\u0e19\u0e22\u0e32\u0e22\u0e19", "\u0e15\u0e38\u0e25\u0e32\u0e04\u0e21", "\u0e1e\u0e24\u0e28\u0e08\u0e34\u0e01\u0e32\u0e22\u0e19", "\u0e18\u0e31\u0e19\u0e27\u0e32\u0e04\u0e21", } // monthNamesTibetan list the month names in the Tibetan. monthNamesTibetan = []string{ "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f51\u0f44\u0f0b\u0f54\u0f7c\u0f0b", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f42\u0f49\u0f72\u0f66\u0f0b\u0f54\u0f0b", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f42\u0f66\u0f74\u0f58\u0f0b\u0f54\u0f0b", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f5e\u0f72\u0f0b\u0f54\u0f0b", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f63\u0f94\u0f0b\u0f54\u0f0b", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f51\u0fb2\u0f74\u0f42\u0f0b\u0f54\u0f0b", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f51\u0f74\u0f53\u0f0b\u0f54\u0f0b", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f62\u0f92\u0fb1\u0f51\u0f0b\u0f54\u0f0b", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f51\u0f42\u0f74\u0f0b\u0f54\u0f0b", "\u0f66\u0fa4\u0fb1\u0f72\u0f0b\u0f5f\u0fb3\u0f0b\u0f56\u0f45\u0f74\u0f0b\u0f54\u0f0d", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f45\u0f74\u0f0b\u0f42\u0f45\u0f72\u0f42\u0f0b\u0f54\u0f0b", "\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f45\u0f74\u0f0b\u0f42\u0f49\u0f72\u0f66\u0f0b\u0f54\u0f0b", } // monthNamesTibetanAbbr lists the month name abbreviations in Tibetan monthNamesTibetanAbbr = []string{ "\u0f5f\u0fb3\u0f0b\u0f21", "\u0f5f\u0fb3\u0f0b\u0f22", "\u0f5f\u0fb3\u0f0b\u0f23", "\u0f5f\u0fb3\u0f0b\u0f24", "\u0f5f\u0fb3\u0f0b\u0f25", "\u0f5f\u0fb3\u0f0b\u0f26", "\u0f5f\u0fb3\u0f0b\u0f27", "\u0f5f\u0fb3\u0f0b\u0f28", "\u0f5f\u0fb3\u0f0b\u0f29", "\u0f5f\u0fb3\u0f0b\u0f21\u0f20", "\u0f5f\u0fb3\u0f0b\u0f21\u0f21", "\u0f5f\u0fb3\u0f0b\u0f21\u0f22", } // monthNamesTurkish list the month names in the Turkish. monthNamesTurkish = []string{"Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"} // monthNamesTurkishAbbr lists the month name abbreviations in Turkish, this prevents string concatenation monthNamesTurkishAbbr = []string{"Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"} // monthNamesVietnamese list the month name used for Vietnamese monthNamesVietnamese = []string{"Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12"} // monthNamesVietnameseAbbr3 list the mid-form abbreviation for Vietnamese months monthNamesVietnameseAbbr3 = []string{"Thg 1", "Thg 2", "Thg 3", "Thg 4", "Thg 5", "Thg 6", "Thg 7", "Thg 8", "Thg 9", "Thg 10", "Thg 11", "Thg 12"} // monthNamesVietnameseAbbr5 list the short-form abbreviation for Vietnamese months monthNamesVietnameseAbbr5 = []string{"T 1", "T 2", "T 3", "T 4", "T 5", "T 6", "T 7", "T 8", "T 9", "T 10", "T 11", "T 12"} // monthNamesWelsh list the month names in the Welsh. monthNamesWelsh = []string{"Ionawr", "Chwefror", "Mawrth", "Ebrill", "Mai", "Mehefin", "Gorffennaf", "Awst", "Medi", "Hydref", "Tachwedd", "Rhagfyr"} // monthNamesWelshAbbr lists the month name abbreviations in Welsh, this prevents string concatenation monthNamesWelshAbbr = []string{"Ion", "Chwef", "Maw", "Ebr", "Mai", "Meh", "Gorff", "Awst", "Medi", "Hyd", "Tach", "Rhag"} // monthNamesWolof list the month names in the Wolof. monthNamesWolof = []string{"Samwiye", "Fewriye", "Maars", "Awril", "Me", "Suwe", "Sullet", "Ut", "Septàmbar", "Oktoobar", "Noowàmbar", "Desàmbar"} // monthNamesWolofAbbr list the month name abbreviations in Wolof, this prevents string concatenation monthNamesWolofAbbr = []string{"Sam.", "Few.", "Maa", "Awr.", "Me", "Suw", "Sul.", "Ut", "Sept.", "Okt.", "Now.", "Des."} // monthNamesXhosa list the month names in the Xhosa. monthNamesXhosa = []string{"uJanuwari", "uFebuwari", "uMatshi", "uAprili", "uMeyi", "uJuni", "uJulayi", "uAgasti", "uSeptemba", "uOktobha", "uNovemba", "uDisemba"} // monthNamesXhosaAbbr list the month abbreviations in the Xhosa, this prevents string concatenation monthNamesXhosaAbbr = []string{"uJan.", "uFeb.", "uMat.", "uEpr.", "uMey.", "uJun.", "uJul.", "uAg.", "uSep.", "uOkt.", "uNov.", "uDis."} // monthNamesYi list the month names in the Yi. monthNamesYi = []string{"\ua2cd", "\ua44d", "\ua315", "\ua1d6", "\ua26c", "\ua0d8", "\ua3c3", "\ua246", "\ua22c", "\ua2b0", "\ua2b0\ua2aa", "\ua2b0\ua44b"} // monthNamesYiSuffix lists the month names in Yi with the "\ua1aa" suffix monthNamesYiSuffix = []string{"\ua2cd\ua1aa", "\ua44d\ua1aa", "\ua315\ua1aa", "\ua1d6\ua1aa", "\ua26c\ua1aa", "\ua0d8\ua1aa", "\ua3c3\ua1aa", "\ua246\ua1aa", "\ua22c\ua1aa", "\ua2b0\ua1aa", "\ua2b0\ua2aa\ua1aa", "\ua2b0\ua44b\ua1aa"} // monthNamesZulu list the month names in the Zulu. monthNamesZulu = []string{"Januwari", "Febhuwari", "Mashi", "Ephreli", "Meyi", "Juni", "Julayi", "Agasti", "Septemba", "Okthoba", "Novemba", "Disemba"} // monthNamesZuluAbbr list the month name abbreviations in Zulu monthNamesZuluAbbr = []string{"Jan", "Feb", "Mas", "Eph", "Mey", "Jun", "Jul", "Agas", "Sep", "Okt", "Nov", "Dis"} // apFmtAfrikaans defined the AM/PM name in the Afrikaans. apFmtAfrikaans = "vm./nm." // apFmtCuba defined the AM/PM name in the Cuba. apFmtCuba = "a.m./p.m." // apFmtIrish defined the AM/PM name in the Irish. apFmtIrish = "r.n./i.n." // apFmtJapanese defined the AM/PM name in the Japanese. apFmtJapanese = "午前/午後" // apFmtKorean defined the AM/PM name in the Korean. apFmtKorean = "오전/오후" // apFmtSpanish defined the AM/PM name in the Spanish. apFmtSpanish = "a. m./p. m." // apFmtTibetan defined the AM/PM name in the Tibetan. apFmtTibetan = "\u0f66\u0f94\u0f0b\u0f51\u0fb2\u0f7c\u0f0b/\u0f55\u0fb1\u0f72\u0f0b\u0f51\u0fb2\u0f7c\u0f0b" // apFmtTurkish defined the AM/PM name in the Turkish. apFmtTurkish = "\u00F6\u00F6/\u00F6\u0053" // apFmtVietnamese defined the AM/PM name in the Vietnamese. apFmtVietnamese = "SA/CH" // apFmtWolof defined the AM/PM name in the Wolof. apFmtWolof = "Sub/Ngo" // apFmtYi defined the AM/PM name in the Yi. apFmtYi = "\ua3b8\ua111/\ua06f\ua2d2" // apFmtWelsh defined the AM/PM name in the Welsh. apFmtWelsh = "yb/yh" // switchArgumentFunc defined the switch argument printer function switchArgumentFunc = map[string]func(s string) string{ "[DBNum1]": func(s string) string { r := strings.NewReplacer( "0", "\u25cb", "1", "\u4e00", "2", "\u4e8c", "3", "\u4e09", "4", "\u56db", "5", "\u4e94", "6", "\u516d", "7", "\u4e03", "8", "\u516b", "9", "\u4e5d", ) return r.Replace(s) }, "[DBNum2]": func(s string) string { r := strings.NewReplacer( "0", "\u96f6", "1", "\u58f9", "2", "\u8d30", "3", "\u53c1", "4", "\u8086", "5", "\u4f0d", "6", "\u9646", "7", "\u67d2", "8", "\u634c", "9", "\u7396", ) return r.Replace(s) }, "[DBNum3]": func(s string) string { r := strings.NewReplacer( "0", "\uff10", "1", "\uff11", "2", "\uff12", "3", "\uff13", "4", "\uff14", "5", "\uff15", "6", "\uff16", "7", "\uff17", "8", "\uff18", "9", "\uff19", ) return r.Replace(s) }, } ) // applyBuiltInNumFmt provides a function to returns a value after formatted // with built-in number format code, or specified sort date format code. func (f *File) applyBuiltInNumFmt(c *xlsxC, fmtCode string, numFmtID int, date1904 bool, cellType CellType) string { if numFmtID == 14 && f.options != nil && f.options.ShortDatePattern != "" { fmtCode = f.options.ShortDatePattern } return format(c.V, fmtCode, date1904, cellType, f.options) } // langNumFmtFuncEnUS returns number format code by given date and time pattern // for country code en-us. func (f *File) langNumFmtFuncEnUS(numFmtID int) string { shortDatePattern, longTimePattern := "M/d/yy", "h:mm:ss" if f.options.ShortDatePattern != "" { shortDatePattern = f.options.ShortDatePattern } if f.options.LongTimePattern != "" { longTimePattern = f.options.LongTimePattern } if 32 <= numFmtID && numFmtID <= 35 { return longTimePattern } if (27 <= numFmtID && numFmtID <= 31) || (50 <= numFmtID && numFmtID <= 58) { return shortDatePattern } return "" } // checkDateTimePattern check and validate date and time options field value. func (f *File) checkDateTimePattern() error { for _, pattern := range []string{f.options.LongDatePattern, f.options.LongTimePattern, f.options.ShortDatePattern} { p := nfp.NumberFormatParser() for _, section := range p.Parse(pattern) { for _, token := range section.Items { if inStrSlice(supportedTokenTypes, token.TType, false) == -1 || inStrSlice(supportedNumberTokenTypes, token.TType, false) != -1 { return ErrUnsupportedNumberFormat } } } } return nil } // langNumFmtFuncZhCN returns number format code by given date and time pattern // for country code zh-cn. func (f *File) langNumFmtFuncZhCN(numFmtID int) string { if numFmtID == 30 && f.options.ShortDatePattern != "" { return f.options.ShortDatePattern } if (32 <= numFmtID && numFmtID <= 33) && f.options.LongTimePattern != "" { return f.options.LongTimePattern } return langNumFmt["zh-cn"][numFmtID] } // getBuiltInNumFmtCode convert number format index to number format code with // specified locale and language. func (f *File) getBuiltInNumFmtCode(numFmtID int) (string, bool) { if fmtCode, ok := builtInNumFmt[numFmtID]; ok { return fmtCode, true } if (27 <= numFmtID && numFmtID <= 36) || (50 <= numFmtID && numFmtID <= 81) { if f.options.CultureInfo == CultureNameEnUS { return f.langNumFmtFuncEnUS(numFmtID), true } if f.options.CultureInfo == CultureNameZhCN { return f.langNumFmtFuncZhCN(numFmtID), true } } return "", false } // prepareNumberic split the number into two before and after parts by a // decimal point. func (nf *numberFormat) prepareNumberic(value string) { if nf.cellType != CellTypeNumber && nf.cellType != CellTypeDate { return } if nf.isNumeric, _, _ = isNumeric(value); !nf.isNumeric { return } } // format provides a function to return a string parse by number format // expression. If the given number format is not supported, this will return // the original cell value. func format(value, numFmt string, date1904 bool, cellType CellType, opts *Options) string { p := nfp.NumberFormatParser() nf := numberFormat{opts: opts, section: p.Parse(numFmt), value: value, date1904: date1904, cellType: cellType} nf.number, nf.valueSectionType = nf.getValueSectionType(value) nf.prepareNumberic(value) for i, section := range nf.section { nf.sectionIdx = i if section.Type != nf.valueSectionType { continue } if nf.isNumeric { switch section.Type { case nfp.TokenSectionPositive: return nf.positiveHandler() case nfp.TokenSectionNegative: return nf.negativeHandler() default: return nf.zeroHandler() } } return nf.textHandler() } return value } // getNumberPartLen returns the length of integer and fraction parts for the // numeric. func getNumberPartLen(n float64) (int, int) { parts := strings.Split(strconv.FormatFloat(math.Abs(n), 'f', -1, 64), ".") if len(parts) == 2 { return len(parts[0]), len(parts[1]) } return len(parts[0]), 0 } // getNumberFmtConf generate the number format padding and placeholder // configurations. func (nf *numberFormat) getNumberFmtConf() { for _, token := range nf.section[nf.sectionIdx].Items { if token.TType == nfp.TokenTypeHashPlaceHolder { if nf.usePointer { nf.fracHolder += len(token.TValue) } else { nf.intHolder += len(token.TValue) } } if token.TType == nfp.TokenTypeExponential { nf.useScientificNotation = true } if token.TType == nfp.TokenTypeThousandsSeparator { nf.useCommaSep = true } if token.TType == nfp.TokenTypePercent { nf.percent += len(token.TValue) } if token.TType == nfp.TokenTypeDecimalPoint { nf.usePointer = true } if token.TType == nfp.TokenTypeSwitchArgument { nf.switchArgument = token.TValue } if token.TType == nfp.TokenTypeZeroPlaceHolder { if nf.usePointer { if nf.useScientificNotation { nf.expBaseLen += len(token.TValue) continue } nf.fracPadding += len(token.TValue) continue } nf.intPadding += len(token.TValue) } } } // printNumberLiteral apply literal tokens for the pre-formatted text. func (nf *numberFormat) printNumberLiteral(text string) string { var result string var useLiteral, useZeroPlaceHolder bool if nf.usePositive { result += "-" } for _, token := range nf.section[nf.sectionIdx].Items { if token.TType == nfp.TokenTypeCurrencyLanguage { if err, changeNumFmtCode := nf.currencyLanguageHandler(token); err != nil || changeNumFmtCode { return nf.value } result += nf.currencyString } if token.TType == nfp.TokenTypeLiteral { if useZeroPlaceHolder { useLiteral = true } result += token.TValue } if token.TType == nfp.TokenTypeZeroPlaceHolder { if useLiteral && useZeroPlaceHolder { return nf.value } if !useZeroPlaceHolder { useZeroPlaceHolder = true result += text } } } return nf.printSwitchArgument(result) } // printCommaSep format number with thousands separator. func printCommaSep(text string) string { var ( target strings.Builder subStr = strings.Split(text, ".") length = len(subStr[0]) ) for i := 0; i < length; i++ { if i > 0 && (length-i)%3 == 0 { target.WriteString(",") } target.WriteByte(text[i]) } if len(subStr) == 2 { target.WriteString(".") target.WriteString(subStr[1]) } return target.String() } // printSwitchArgument format number with switch argument. func (nf *numberFormat) printSwitchArgument(text string) string { if nf.switchArgument == "" { return text } if fn, ok := switchArgumentFunc[nf.switchArgument]; ok { return fn(text) } return nf.value } // printBigNumber format number which precision great than 15 with fraction // zero padding and percentage symbol. func (nf *numberFormat) printBigNumber(decimal float64, fracLen int) string { var exp float64 if nf.percent > 0 { exp = 1 } result := strings.TrimLeft(strconv.FormatFloat(decimal*math.Pow(100, exp), 'f', -1, 64), "-") if nf.useCommaSep { result = printCommaSep(result) } if fracLen > 0 { if parts := strings.Split(result, "."); len(parts) == 2 { fracPartLen := len(parts[1]) if fracPartLen < fracLen { result = fmt.Sprintf("%s%s", result, strings.Repeat("0", fracLen-fracPartLen)) } if fracPartLen > fracLen { result = fmt.Sprintf("%s.%s", parts[0], parts[1][:fracLen]) } } else { result = fmt.Sprintf("%s.%s", result, strings.Repeat("0", fracLen)) } } if nf.percent > 0 { return fmt.Sprintf("%s%%", result) } return result } // numberHandler handling number format expression for positive and negative // numeric. func (nf *numberFormat) numberHandler() string { var ( num = nf.number intPart, fracPart = getNumberPartLen(nf.number) intLen, fracLen int result string ) nf.getNumberFmtConf() if intLen = intPart; nf.intPadding > intPart { intLen = nf.intPadding } if fracLen = fracPart; fracPart > nf.fracHolder+nf.fracPadding { fracLen = nf.fracHolder + nf.fracPadding } if nf.fracPadding > fracPart { fracLen = nf.fracPadding } if isNum, precision, decimal := isNumeric(nf.value); isNum { if precision > 15 && intLen+fracLen > 15 { return nf.printNumberLiteral(nf.printBigNumber(decimal, fracLen)) } } paddingLen := intLen + fracLen if fracLen > 0 { paddingLen++ } flag := "f" if nf.useScientificNotation { if nf.expBaseLen != 2 { return nf.value } flag = "E" } fmtCode := fmt.Sprintf("%%0%d.%d%s%s", paddingLen, fracLen, flag, strings.Repeat("%%", nf.percent)) if nf.percent > 0 { num *= math.Pow(100, float64(nf.percent)) } if result = fmt.Sprintf(fmtCode, math.Abs(num)); nf.useCommaSep { result = printCommaSep(result) } return nf.printNumberLiteral(result) } // dateTimeHandler handling data and time number format expression for a // positive numeric. func (nf *numberFormat) dateTimeHandler() string { nf.t, nf.hours, nf.seconds = timeFromExcelTime(nf.number, nf.date1904), false, false for i, token := range nf.section[nf.sectionIdx].Items { if token.TType == nfp.TokenTypeCurrencyLanguage { if err, changeNumFmtCode := nf.currencyLanguageHandler(token); err != nil || changeNumFmtCode { return nf.value } nf.result += nf.currencyString } if token.TType == nfp.TokenTypeDateTimes { nf.dateTimesHandler(i, token) } if token.TType == nfp.TokenTypeElapsedDateTimes { nf.elapsedDateTimesHandler(token) } if token.TType == nfp.TokenTypeLiteral { nf.result += token.TValue continue } if token.TType == nfp.TokenTypeDecimalPoint { nf.result += "." } if token.TType == nfp.TokenTypeSwitchArgument { nf.switchArgument = token.TValue } if token.TType == nfp.TokenTypeZeroPlaceHolder { zeroHolderLen := len(token.TValue) if zeroHolderLen > 3 { zeroHolderLen = 3 } nf.result += fmt.Sprintf("%03d", nf.t.Nanosecond()/1e6)[:zeroHolderLen] } } return nf.printSwitchArgument(nf.result) } // positiveHandler will be handling positive selection for a number format // expression. func (nf *numberFormat) positiveHandler() string { var fmtNum bool for _, token := range nf.section[nf.sectionIdx].Items { if inStrSlice(supportedTokenTypes, token.TType, true) == -1 || token.TType == nfp.TokenTypeGeneral { return nf.value } if inStrSlice(supportedNumberTokenTypes, token.TType, true) != -1 { fmtNum = true } if inStrSlice(supportedDateTimeTokenTypes, token.TType, true) != -1 { if fmtNum || nf.number < 0 { return nf.value } var useDateTimeTokens bool for _, token := range nf.section[nf.sectionIdx].Items { if inStrSlice(supportedDateTimeTokenTypes, token.TType, false) != -1 { if useDateTimeTokens && nf.useMillisecond { return nf.value } useDateTimeTokens = true } if inStrSlice(supportedNumberTokenTypes, token.TType, false) != -1 { if token.TType == nfp.TokenTypeZeroPlaceHolder { nf.useMillisecond = true continue } return nf.value } } return nf.dateTimeHandler() } } return nf.numberHandler() } // currencyLanguageHandler will be handling currency and language types tokens // for a number format expression. func (nf *numberFormat) currencyLanguageHandler(token nfp.Token) (error, bool) { for _, part := range token.Parts { if inStrSlice(supportedTokenTypes, part.Token.TType, true) == -1 { return ErrUnsupportedNumberFormat, false } if part.Token.TType == nfp.TokenSubTypeLanguageInfo { if strings.EqualFold(part.Token.TValue, "F800") { // [$-x-sysdate] if nf.opts != nil && nf.opts.LongDatePattern != "" { nf.value = format(nf.value, nf.opts.LongDatePattern, nf.date1904, nf.cellType, nf.opts) return nil, true } part.Token.TValue = "409" } if strings.EqualFold(part.Token.TValue, "F400") { // [$-x-systime] if nf.opts != nil && nf.opts.LongTimePattern != "" { nf.value = format(nf.value, nf.opts.LongTimePattern, nf.date1904, nf.cellType, nf.opts) return nil, true } part.Token.TValue = "409" } if _, ok := supportedLanguageInfo[strings.ToUpper(part.Token.TValue)]; !ok { return ErrUnsupportedNumberFormat, false } nf.localCode = strings.ToUpper(part.Token.TValue) } if part.Token.TType == nfp.TokenSubTypeCurrencyString { nf.currencyString = part.Token.TValue } } return nil, false } // localAmPm return AM/PM name by supported language ID. func (nf *numberFormat) localAmPm(ap string) string { if languageInfo, ok := supportedLanguageInfo[nf.localCode]; ok { return languageInfo.apFmt } return ap } // localMonthsNameEnglish returns the English name of the month. func localMonthsNameEnglish(t time.Time, abbr int) string { if abbr == 3 { return t.Month().String()[:3] } if abbr == 4 { return t.Month().String() } return t.Month().String()[:1] } // localMonthsNameAfrikaans returns the Afrikaans name of the month. func localMonthsNameAfrikaans(t time.Time, abbr int) string { if abbr == 3 { return monthNamesAfrikaansAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesAfrikaans[int(t.Month())-1] } return monthNamesAfrikaansAbbr[int(t.Month())-1][:1] } // localMonthsNameAustria returns the Austria name of the month. func localMonthsNameAustria(t time.Time, abbr int) string { if abbr == 3 { return monthNamesAustriaAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesAustria[int(t.Month())-1] } return monthNamesAustriaAbbr[int(t.Month())-1][:1] } // localMonthsNameBangla returns the German name of the month. func localMonthsNameBangla(t time.Time, abbr int) string { if abbr == 3 || abbr == 4 { return monthNamesBangla[int(t.Month())-1] } return string([]rune(monthNamesBangla[int(t.Month())-1])[:1]) } // localMonthsNameFrench returns the French name of the month. func localMonthsNameFrench(t time.Time, abbr int) string { if abbr == 3 { month := monthNamesFrench[int(t.Month())-1] if len([]rune(month)) <= 4 { return monthNamesFrench[int(t.Month())-1] } return monthNamesFrenchAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesFrench[int(t.Month())-1] } return monthNamesFrenchAbbr[int(t.Month())-1][:1] } // localMonthsNameIrish returns the Irish name of the month. func localMonthsNameIrish(t time.Time, abbr int) string { if abbr == 3 { return monthNamesIrishAbbr[(t.Month() - 1)] } if abbr == 4 { return monthNamesIrish[int(t.Month())-1] } return monthNamesIrishAbbr[int(t.Month())-1][:1] } // localMonthsNameItalian returns the Italian name of the month. func localMonthsNameItalian(t time.Time, abbr int) string { if abbr == 3 { return monthNamesItalianAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesItalian[int(t.Month())-1] } return monthNamesItalianAbbr[int(t.Month())-1][:1] } // localMonthsNameGerman returns the German name of the month. func localMonthsNameGerman(t time.Time, abbr int) string { if abbr == 3 { return monthNamesGermanAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesGerman[int(t.Month())-1] } return monthNamesGermanAbbr[int(t.Month())-1][:1] } // localMonthsNameChinese1 returns the Chinese name of the month. func localMonthsNameChinese1(t time.Time, abbr int) string { if abbr == 3 { return monthNamesChineseAbbrPlus[t.Month()] } if abbr == 4 { return monthNamesChinesePlus[int(t.Month())-1] } return monthNamesChinese[int(t.Month())-1] } // localMonthsNameChinese2 returns the Chinese name of the month. func localMonthsNameChinese2(t time.Time, abbr int) string { if abbr == 3 || abbr == 4 { return monthNamesChinesePlus[int(t.Month())-1] } return monthNamesChinese[int(t.Month())-1] } // localMonthsNameChinese3 returns the Chinese name of the month. func localMonthsNameChinese3(t time.Time, abbr int) string { if abbr == 3 || abbr == 4 { return monthNamesChineseAbbrPlus[t.Month()] } return strconv.Itoa(int(t.Month())) } // localMonthsNameKorean returns the Korean name of the month. func localMonthsNameKorean(t time.Time, abbr int) string { if abbr == 3 || abbr == 4 { return monthNamesKoreanAbbrPlus[t.Month()] } return strconv.Itoa(int(t.Month())) } // localMonthsNameTraditionalMongolian returns the Traditional Mongolian name of // the month. func localMonthsNameTraditionalMongolian(t time.Time, abbr int) string { if abbr == 5 { return "M" } return monthNamesTradMongolian[t.Month()-1] } // localMonthsNameRussian returns the Russian name of the month. func localMonthsNameRussian(t time.Time, abbr int) string { if abbr == 3 { month := monthNamesRussian[int(t.Month())-1] if len([]rune(month)) <= 4 { return month } return monthNamesRussianAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesRussian[int(t.Month())-1] } return string([]rune(monthNamesRussian[int(t.Month())-1])[:1]) } // localMonthsNameSpanish returns the Spanish name of the month. func localMonthsNameSpanish(t time.Time, abbr int) string { if abbr == 3 { return monthNamesSpanishAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesSpanish[int(t.Month())-1] } return monthNamesSpanishAbbr[int(t.Month())-1][:1] } // localMonthsNameThai returns the Thai name of the month. func localMonthsNameThai(t time.Time, abbr int) string { if abbr == 3 { r := []rune(monthNamesThai[int(t.Month())-1]) return string(r[:1]) + "." + string(r[len(r)-2:len(r)-1]) + "." } if abbr == 4 { return monthNamesThai[int(t.Month())-1] } return string([]rune(monthNamesThai[int(t.Month())-1])[:1]) } // localMonthsNameTibetan returns the Tibetan name of the month. func localMonthsNameTibetan(t time.Time, abbr int) string { if abbr == 3 { return monthNamesTibetanAbbr[int(t.Month())-1] } if abbr == 5 { if t.Month() == 10 { return "\u0f66" } return "\u0f5f" } return monthNamesTibetan[int(t.Month())-1] } // localMonthsNameTurkish returns the Turkish name of the month. func localMonthsNameTurkish(t time.Time, abbr int) string { if abbr == 3 { return monthNamesTurkishAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesTurkish[int(t.Month())-1] } return string([]rune(monthNamesTurkishAbbr[int(t.Month())-1])[:1]) } // localMonthsNameWelsh returns the Welsh name of the month. func localMonthsNameWelsh(t time.Time, abbr int) string { if abbr == 3 { return monthNamesWelshAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesWelsh[int(t.Month())-1] } return monthNamesWelshAbbr[int(t.Month())-1][:1] } // localMonthsNameVietnamese returns the Vietnamese name of the month. func localMonthsNameVietnamese(t time.Time, abbr int) string { if abbr == 3 { return monthNamesVietnameseAbbr3[t.Month()-1] } if abbr == 5 { return monthNamesVietnameseAbbr5[t.Month()-1] } return monthNamesVietnamese[t.Month()-1] } // localMonthsNameWolof returns the Wolof name of the month. func localMonthsNameWolof(t time.Time, abbr int) string { if abbr == 3 { return monthNamesWolofAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesWolof[int(t.Month())-1] } return monthNamesWolof[int(t.Month())-1][:1] } // localMonthsNameXhosa returns the Xhosa name of the month. func localMonthsNameXhosa(t time.Time, abbr int) string { if abbr == 3 { return monthNamesXhosaAbbr[int(t.Month())-1] } if abbr == 4 { return monthNamesXhosa[int(t.Month())-1] } return "u" } // localMonthsNameYi returns the Yi name of the month. func localMonthsNameYi(t time.Time, abbr int) string { if abbr == 3 || abbr == 4 { return monthNamesYiSuffix[t.Month()-1] } return string([]rune(monthNamesYi[int(t.Month())-1])[:1]) } // localMonthsNameZulu returns the Zulu name of the month. func localMonthsNameZulu(t time.Time, abbr int) string { if abbr == 3 { return monthNamesZuluAbbr[t.Month()-1] } if abbr == 4 { return monthNamesZulu[int(t.Month())-1] } return monthNamesZuluAbbr[int(t.Month())-1][:1] } // localMonthName return months name by supported language ID. func (nf *numberFormat) localMonthsName(abbr int) string { if languageInfo, ok := supportedLanguageInfo[nf.localCode]; ok { return languageInfo.localMonth(nf.t, abbr) } return localMonthsNameEnglish(nf.t, abbr) } // dateTimesHandler will be handling date and times types tokens for a number // format expression. func (nf *numberFormat) dateTimesHandler(i int, token nfp.Token) { if idx := inStrSlice(nfp.AmPm, strings.ToUpper(token.TValue), false); idx != -1 { if nf.ap == "" { nextHours := nf.hoursNext(i) aps := strings.Split(nf.localAmPm(token.TValue), "/") nf.ap = aps[0] if nextHours >= 12 { nf.ap = aps[1] } } nf.result += nf.ap return } if strings.Contains(strings.ToUpper(token.TValue), "M") { l := len(token.TValue) if l == 1 && !nf.hours && !nf.secondsNext(i) { nf.result += strconv.Itoa(int(nf.t.Month())) return } if l == 2 && !nf.hours && !nf.secondsNext(i) { nf.result += fmt.Sprintf("%02d", int(nf.t.Month())) return } if l == 3 { nf.result += nf.localMonthsName(3) return } if l == 4 || l > 5 { nf.result += nf.localMonthsName(4) return } if l == 5 { nf.result += nf.localMonthsName(5) return } } nf.yearsHandler(token) nf.daysHandler(token) nf.hoursHandler(i, token) nf.minutesHandler(token) nf.secondsHandler(token) } // yearsHandler will be handling years in the date and times types tokens for a // number format expression. func (nf *numberFormat) yearsHandler(token nfp.Token) { years := strings.Contains(strings.ToUpper(token.TValue), "Y") if years && len(token.TValue) <= 2 { nf.result += strconv.Itoa(nf.t.Year())[2:] return } if years && len(token.TValue) > 2 { nf.result += strconv.Itoa(nf.t.Year()) return } } // daysHandler will be handling days in the date and times types tokens for a // number format expression. func (nf *numberFormat) daysHandler(token nfp.Token) { if strings.Contains(strings.ToUpper(token.TValue), "D") { switch len(token.TValue) { case 1: nf.result += strconv.Itoa(nf.t.Day()) return case 2: nf.result += fmt.Sprintf("%02d", nf.t.Day()) return case 3: nf.result += nf.t.Weekday().String()[:3] return default: nf.result += nf.t.Weekday().String() return } } } // hoursHandler will be handling hours in the date and times types tokens for a // number format expression. func (nf *numberFormat) hoursHandler(i int, token nfp.Token) { nf.hours = strings.Contains(strings.ToUpper(token.TValue), "H") if nf.hours { h := nf.t.Hour() ap, ok := nf.apNext(i) if ok { nf.ap = ap[0] if h >= 12 { nf.ap = ap[1] } if h > 12 { h -= 12 } } if nf.ap != "" { if nf.hoursNext(i) == -1 && h > 12 { h -= 12 } if h == 0 { h = 12 } } switch len(token.TValue) { case 1: nf.result += strconv.Itoa(h) return default: nf.result += fmt.Sprintf("%02d", h) return } } } // minutesHandler will be handling minutes in the date and times types tokens // for a number format expression. func (nf *numberFormat) minutesHandler(token nfp.Token) { if strings.Contains(strings.ToUpper(token.TValue), "M") { nf.hours = false switch len(token.TValue) { case 1: nf.result += strconv.Itoa(nf.t.Minute()) return default: nf.result += fmt.Sprintf("%02d", nf.t.Minute()) return } } } // secondsHandler will be handling seconds in the date and times types tokens // for a number format expression. func (nf *numberFormat) secondsHandler(token nfp.Token) { if nf.seconds = strings.Contains(strings.ToUpper(token.TValue), "S"); !nf.seconds { return } if !nf.useMillisecond { nf.t = nf.t.Add(time.Duration(math.Round(float64(nf.t.Nanosecond())/1e9)) * time.Second) } if len(token.TValue) == 1 { nf.result += strconv.Itoa(nf.t.Second()) return } nf.result += fmt.Sprintf("%02d", nf.t.Second()) } // elapsedDateTimesHandler will be handling elapsed date and times types tokens // for a number format expression. func (nf *numberFormat) elapsedDateTimesHandler(token nfp.Token) { if strings.Contains(strings.ToUpper(token.TValue), "H") { nf.result += fmt.Sprintf("%.f", nf.t.Sub(excel1900Epoc).Hours()) return } if strings.Contains(strings.ToUpper(token.TValue), "M") { nf.result += fmt.Sprintf("%.f", nf.t.Sub(excel1900Epoc).Minutes()) return } if strings.Contains(strings.ToUpper(token.TValue), "S") { nf.result += fmt.Sprintf("%.f", nf.t.Sub(excel1900Epoc).Seconds()) return } } // hoursNext detects if a token of type hours exists after a given tokens list. func (nf *numberFormat) hoursNext(i int) int { tokens := nf.section[nf.sectionIdx].Items for idx := i + 1; idx < len(tokens); idx++ { if tokens[idx].TType == nfp.TokenTypeDateTimes { if strings.Contains(strings.ToUpper(tokens[idx].TValue), "H") { t := timeFromExcelTime(nf.number, false) return t.Hour() } } } return -1 } // apNext detects if a token of type AM/PM exists after a given tokens list. func (nf *numberFormat) apNext(i int) ([]string, bool) { tokens := nf.section[nf.sectionIdx].Items for idx := i + 1; idx < len(tokens); idx++ { if tokens[idx].TType == nfp.TokenTypeDateTimes { if strings.Contains(strings.ToUpper(tokens[idx].TValue), "H") { return nil, false } if i := inStrSlice(nfp.AmPm, tokens[idx].TValue, false); i != -1 { return strings.Split(nf.localAmPm(tokens[idx].TValue), "/"), true } } } return nil, false } // secondsNext detects if a token of type seconds exists after a given tokens // list. func (nf *numberFormat) secondsNext(i int) bool { tokens := nf.section[nf.sectionIdx].Items for idx := i + 1; idx < len(tokens); idx++ { if tokens[idx].TType == nfp.TokenTypeDateTimes { return strings.Contains(strings.ToUpper(tokens[idx].TValue), "S") } } return false } // negativeHandler will be handling negative selection for a number format // expression. func (nf *numberFormat) negativeHandler() (result string) { for _, token := range nf.section[nf.sectionIdx].Items { if inStrSlice(supportedTokenTypes, token.TType, true) == -1 || token.TType == nfp.TokenTypeGeneral { return nf.value } if inStrSlice(supportedDateTimeTokenTypes, token.TType, true) != -1 { return nf.value } } return nf.numberHandler() } // zeroHandler will be handling zero selection for a number format expression. func (nf *numberFormat) zeroHandler() string { return nf.value } // textHandler will be handling text selection for a number format expression. func (nf *numberFormat) textHandler() (result string) { for _, token := range nf.section[nf.sectionIdx].Items { if token.TType == nfp.TokenTypeLiteral { result += token.TValue } if token.TType == nfp.TokenTypeTextPlaceHolder || token.TType == nfp.TokenTypeZeroPlaceHolder { result += nf.value } } return result } // getValueSectionType returns its applicable number format expression section // based on the given value. func (nf *numberFormat) getValueSectionType(value string) (float64, string) { if nf.cellType != CellTypeNumber && nf.cellType != CellTypeDate { return 0, nfp.TokenSectionText } isNum, _, _ := isNumeric(value) if !isNum { return 0, nfp.TokenSectionText } number, _ := strconv.ParseFloat(value, 64) if number > 0 { return number, nfp.TokenSectionPositive } if number < 0 { var hasNeg bool for _, sec := range nf.section { if sec.Type == nfp.TokenSectionNegative { hasNeg = true } } if !hasNeg { nf.usePositive = true return number, nfp.TokenSectionPositive } return number, nfp.TokenSectionNegative } return number, nfp.TokenSectionZero }