Browse Source

[Bug 60422] fix data formatter issue with specific format in German locale

pull/1589/head
Antony Liu 1 month ago
parent
commit
5742abfd75
  1. 15
      main/SS/Format/CellDateFormatter.cs
  2. 74
      main/SS/Format/CellFormat.cs
  3. 20
      main/SS/Format/CellFormatPart.cs
  4. 32
      main/SS/Format/CellFormatType.cs
  5. 15
      main/SS/Format/CellFormatter.cs
  6. 17
      main/SS/Format/CellGeneralFormatter.cs
  7. 164
      main/SS/Format/CellNumberFormatter.cs
  8. 26
      main/SS/UserModel/DataFormatter.cs
  9. 21
      testcases/main/SS/UserModel/TestDataFormatter.cs

15
main/SS/Format/CellDateFormatter.cs

@ -20,6 +20,7 @@ using System.Text.RegularExpressions;
using System.Text;
using NPOI.SS.Util;
using System.Globalization;
using NPOI.Util;
namespace NPOI.SS.Format
{
@ -159,6 +160,18 @@ namespace NPOI.SS.Format
* @param format The format.
*/
public CellDateFormatter(String format)
: this(LocaleUtil.GetUserLocale(), format)
{
}
/**
* Creates a new date formatter with the given specification.
*
* @param locale The locale.
* @param format The format.
*/
public CellDateFormatter(CultureInfo locale, String format)
: base(format)
{
DatePartHandler partHandler = new DatePartHandler(this);
@ -171,7 +184,7 @@ namespace NPOI.SS.Format
// See https://issues.apache.org/bugzilla/show_bug.cgi?id=53369
String ptrn = Regex.Replace(descBuf.ToString(), "((y)(?!y))(?<!yy)", "yy");
dateFmt = new SimpleDateFormat(ptrn);
dateFmt = new SimpleDateFormat(ptrn, locale);
}
/** {@inheritDoc} */

74
main/SS/Format/CellFormat.cs

@ -17,12 +17,12 @@
namespace NPOI.SS.Format
{
using System;
using NPOI.SS.UserModel;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using NPOI.Util;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
/**
* Format a value according to the standard Excel behavior. This "standard" is
@ -72,6 +72,7 @@ namespace NPOI.SS.Format
*/
public class CellFormat
{
private CultureInfo locale;
private readonly String format;
private readonly CellFormatPart posNumFmt;
private readonly CellFormatPart zeroNumFmt;
@ -81,9 +82,6 @@ namespace NPOI.SS.Format
private static readonly Regex ONE_PART = new Regex(CellFormatPart.FORMAT_PAT.ToString() + "(;|$)", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);
private static readonly CellFormatPart DEFAULT_TEXT_FORMAT =
new CellFormatPart("@");
/*
* Cells that cannot be formatted, e.g. cells that have a date or time
* format and have an invalid date or time value, are displayed as 255
@ -97,28 +95,32 @@ namespace NPOI.SS.Format
"###################################################";
private const string QUOTE = "\"";
private static readonly CellFormat GENERAL_FORMAT = new GeneralCellFormat();
[Obsolete("use {@link #getInstance(Locale, \"General\")} instead")]
private static readonly CellFormat GENERAL_FORMAT = CreateGeneralFormat(LocaleUtil.GetUserLocale());
/**
* Format a value as it would be were no format specified. This is also
* used when the format specified is <tt>General</tt>.
*/
public class GeneralCellFormat : CellFormat
{
public GeneralCellFormat()
: base("General")
public GeneralCellFormat(CultureInfo locale)
: base(locale, "General")
{
}
public override CellFormatResult Apply(Object value)
{
String text = (new CellGeneralFormatter()).Format(value);
String text = (new CellGeneralFormatter(locale)).Format(value);
return new CellFormatResult(true, text, POIUtils.Color_Empty);
}
}
private static GeneralCellFormat CreateGeneralFormat(CultureInfo locale)
{
return new GeneralCellFormat(locale);
}
/** Maps a format string to its Parsed version for efficiencies sake. */
private static readonly Dictionary<String, CellFormat> formatCache =
new Dictionary<String, CellFormat>();
private static Dictionary<CultureInfo, Dictionary<String, CellFormat>> formatCache =
new Dictionary<CultureInfo, Dictionary<String, CellFormat>>();
/**
* Returns a {@link CellFormat} that applies the given format. Two calls
@ -130,28 +132,48 @@ namespace NPOI.SS.Format
*/
public static CellFormat GetInstance(String format)
{
return GetInstance(LocaleUtil.GetUserLocale(), format);
}
/**
* Returns a {@link CellFormat} that applies the given format. Two calls
* with the same format may or may not return the same object.
*
* @param locale The locale.
* @param format The format.
*
* @return A {@link CellFormat} that applies the given format.
*/
public static CellFormat GetInstance(CultureInfo locale, String format)
{
Dictionary<String, CellFormat> formatMap = formatCache.TryGetValue(locale, out Dictionary<string, CellFormat> value) ? value : null;
if (formatMap == null)
{
formatMap = new Dictionary<String, CellFormat>();
formatCache[locale] = formatMap;
}
CellFormat fmt = null;
if (formatCache.TryGetValue(format, out CellFormat value))
fmt = value;
if (formatMap.TryGetValue(format, out CellFormat value1))
fmt = value1;
if (fmt == null)
{
if (format.Equals("General") || format.Equals("@"))
fmt = GENERAL_FORMAT;
fmt = CreateGeneralFormat(locale);
else
fmt = new CellFormat(format);
formatCache.Add(format, fmt);
fmt = new CellFormat(locale, format);
formatMap.Add(format, fmt);
}
return fmt;
}
/**
* Creates a new object.
*
* @param format The format.
*/
private CellFormat(String format)
private CellFormat(CultureInfo locale, String format)
{
this.locale = locale;
this.format = format;
CellFormatPart defaultTextFormat = new CellFormatPart(locale, "@");
MatchCollection mc = ONE_PART.Matches(format);
List<CellFormatPart> parts = new List<CellFormatPart>();
@ -166,7 +188,7 @@ namespace NPOI.SS.Format
if (valueDesc.EndsWith(';'))
valueDesc = valueDesc.Substring(0, valueDesc.Length - 1);
parts.Add(new CellFormatPart(valueDesc));
parts.Add(new CellFormatPart(locale, valueDesc));
}
catch
{
@ -182,19 +204,19 @@ namespace NPOI.SS.Format
posNumFmt = parts[(0)];
negNumFmt = null;
zeroNumFmt = null;
textFmt = DEFAULT_TEXT_FORMAT;
textFmt = defaultTextFormat;
break;
case 2:
posNumFmt = parts[0];
negNumFmt = parts[1];
zeroNumFmt = null;
textFmt = DEFAULT_TEXT_FORMAT;
textFmt = defaultTextFormat;
break;
case 3:
posNumFmt = parts[0];
negNumFmt = parts[1];
zeroNumFmt = parts[2];
textFmt = DEFAULT_TEXT_FORMAT;
textFmt = defaultTextFormat;
break;
case 4:
default:
@ -335,7 +357,7 @@ namespace NPOI.SS.Format
}
else
{
return new CellFormatPart("General");
return new CellFormatPart(locale, "General");
}
}
else if (formatPartCount == 2)

20
main/SS/Format/CellFormatPart.cs

@ -22,8 +22,8 @@ namespace NPOI.SS.Format
using System.Collections.Generic;
using System.Collections;
using System.Text.RegularExpressions;
using System.Text;
using Cysharp.Text;
using System.Text;using Cysharp.Text;
using System.Globalization;
using SixLabors.ImageSharp;
using NPOI.Util;
@ -196,6 +196,16 @@ using Cysharp.Text;
* @param desc The string to Parse.
*/
public CellFormatPart(String desc)
: this(LocaleUtil.GetUserLocale(), desc)
{
}
/**
* Create an object to represent a format part.
*
* @param locale The locale to use.
* @param desc The string to parse.
*/
public CellFormatPart(CultureInfo locale, String desc)
{
Match m = FORMAT_PAT.Match(desc);
if (!m.Success)
@ -205,7 +215,7 @@ using Cysharp.Text;
color = GetColor(m);
condition = GetCondition(m);
type = GetCellFormatType(m);
format = GetFormatter(m);
format = GetFormatter(locale, m);
}
/**
@ -322,7 +332,7 @@ using Cysharp.Text;
*
* @return The formatter.
*/
private CellFormatter GetFormatter(Match matcher)
private CellFormatter GetFormatter(CultureInfo locale, Match matcher)
{
String fdesc = matcher.Groups[(SPECIFICATION_GROUP)].Value;
// For now, we don't support localised currencies, so simplify if there
@ -344,7 +354,7 @@ using Cysharp.Text;
}
// Build a formatter for this simplified string
return type.Formatter(fdesc);
return type.Formatter(locale, fdesc);
}
/**

32
main/SS/Format/CellFormatType.cs

@ -16,6 +16,7 @@
==================================================================== */
using System;
using System.Globalization;
namespace NPOI.SS.Format
{
@ -29,6 +30,10 @@ namespace NPOI.SS.Format
{
return false;
}
public override CellFormatter Formatter(CultureInfo locale, String pattern)
{
return new CellGeneralFormatter(locale);
}
}
internal sealed class NumberCellFormatType : CellFormatType
@ -41,6 +46,10 @@ namespace NPOI.SS.Format
{
return false;
}
public override CellFormatter Formatter(CultureInfo locale, String pattern)
{
return new CellNumberFormatter(locale, pattern);
}
}
internal sealed class DateCellFormatType : CellFormatType
@ -53,6 +62,10 @@ namespace NPOI.SS.Format
{
return new CellDateFormatter(pattern);
}
public override CellFormatter Formatter(CultureInfo locale, String pattern)
{
return new CellDateFormatter(locale, pattern);
}
}
internal sealed class ElapsedCellFormatType : CellFormatType
@ -65,6 +78,10 @@ namespace NPOI.SS.Format
{
return new CellElapsedFormatter(pattern);
}
public override CellFormatter Formatter(CultureInfo locale, String pattern)
{
return new CellElapsedFormatter(pattern);
}
}
internal sealed class TextCellFormatType : CellFormatType
@ -77,6 +94,10 @@ namespace NPOI.SS.Format
{
return new CellTextFormatter(pattern);
}
public override CellFormatter Formatter(CultureInfo locale, String pattern)
{
return new CellTextFormatter(pattern);
}
}
/**
@ -115,5 +136,16 @@ namespace NPOI.SS.Format
* @return A new formatter of the appropriate type, for the given pattern.
*/
public abstract CellFormatter Formatter(String pattern);
/**
* Returns a new formatter of the appropriate type, for the given pattern.
* The pattern must be appropriate for the type.
*
* @param locale The locale to use.
* @param pattern The pattern to use.
*
* @return A new formatter of the appropriate type, for the given pattern.
*/
public abstract CellFormatter Formatter(CultureInfo locale, String pattern);
}
}

15
main/SS/Format/CellFormatter.cs

@ -19,6 +19,7 @@ namespace NPOI.SS.Format
using System;
using System.Text;
using System.Globalization;
using NPOI.Util;
@ -32,7 +33,7 @@ namespace NPOI.SS.Format
{
/** The original specified format. */
protected String format;
protected CultureInfo locale;
/**
* This is the locale used to Get a consistent format result from which to
* work.
@ -45,7 +46,19 @@ namespace NPOI.SS.Format
* @param format The format.
*/
public CellFormatter(String format)
: this(LocaleUtil.GetUserLocale(), format)
{
}
/**
* Creates a new formatter object, storing the format in {@link #format}.
*
* @param locale The locale.
* @param format The format.
*/
public CellFormatter(CultureInfo locale, String format)
{
this.locale = locale;
this.format = format;
}

17
main/SS/Format/CellGeneralFormatter.cs

@ -17,8 +17,10 @@
namespace NPOI.SS.Format
{
using System;
using System.Globalization;
using System.Runtime.Serialization;
using System.Text;
using NPOI.Util;
/**
@ -30,10 +32,15 @@ namespace NPOI.SS.Format
{
/** Creates a new general formatter. */
public CellGeneralFormatter()
: base("General")
: this(LocaleUtil.GetUserLocale())
{
;
}
/** Creates a new general formatter. */
public CellGeneralFormatter(CultureInfo locale)
: base(locale, "General")
{
}
/**
* The general style is not quite the same as any other, or any combination
@ -67,10 +74,8 @@ namespace NPOI.SS.Format
fmt = "F0";
stripZeros = false;
}
toAppendTo.Append(val.ToString(fmt));
toAppendTo.Append(val.ToString(fmt, locale));
//Formatter formatter = new Formatter(toAppendTo);
//formatter.Format(LOCALE, fmt, value);
if (stripZeros)
{
// strip off trailing zeros

164
main/SS/Format/CellNumberFormatter.cs

@ -18,9 +18,10 @@
using System;
using System.Text;
using System.Collections.Generic;
using NPOI.SS.Util;
using System.Collections;
using System.Globalization;
using NPOI.Util;
namespace NPOI.SS.Format
{
@ -40,7 +41,7 @@ namespace NPOI.SS.Format
private Special numerator;
private Special afterInteger;
private Special afterFractional;
private bool integerCommas;
private bool showGroupingSeparator;
private List<Special> specials = new List<Special>();
private List<Special> integerSpecials = new List<Special>();
private List<Special> fractionalSpecials = new List<Special>();
@ -55,10 +56,9 @@ namespace NPOI.SS.Format
private DecimalFormat decimalFmt;
private static List<Special> EmptySpecialList = new List<Special>();
private static readonly SimpleNumberCellFormatter SIMPLE_NUMBER = new SimpleNumberCellFormatter("General");
private static readonly CellNumberFormatter SIMPLE_INT = new CellNumberFormatter("#");
private static readonly CellNumberFormatter SIMPLE_FLOAT = new CellNumberFormatter("#.#");
private readonly GeneralNumberFormatter SIMPLE_NUMBER;
/// <summary>
/// The CellNumberFormatter.simpleValue() method uses the SIMPLE_NUMBER
/// CellFormatter defined here. The CellFormat.GENERAL_FORMAT CellFormat
@ -70,8 +70,8 @@ namespace NPOI.SS.Format
/// </summary>
private sealed class GeneralNumberFormatter : CellFormatter
{
private GeneralNumberFormatter()
: base("General")
public GeneralNumberFormatter(CultureInfo locale)
: base(locale, "General")
{
}
@ -89,7 +89,8 @@ namespace NPOI.SS.Format
{
double num;
double.TryParse(value.ToString(), out num);
cf = (num % 1.0 == 0) ? SIMPLE_INT : SIMPLE_FLOAT;
cf = (num % 1.0 == 0) ? new CellNumberFormatter(locale, "#") :
new CellNumberFormatter(locale, "#.#");
}
else
{
@ -104,40 +105,6 @@ namespace NPOI.SS.Format
}
}
private sealed class SimpleNumberCellFormatter : CellFormatter
{
public SimpleNumberCellFormatter(string format)
: base(format)
{
}
public override void FormatValue(StringBuilder toAppendTo, Object value)
{
if (value == null)
return;
//if (value is Number) {
if (NPOI.Util.Number.IsNumber(value))
{
double num;
double.TryParse(value.ToString(), out num);
if (num % 1.0 == 0)
SIMPLE_INT.FormatValue(toAppendTo, value);
else
SIMPLE_FLOAT.FormatValue(toAppendTo, value);
}
else
{
CellTextFormatter.SIMPLE_TEXT.FormatValue(toAppendTo, value);
}
}
public override void SimpleValue(StringBuilder toAppendTo, Object value)
{
FormatValue(toAppendTo, value);
}
}
/**
* This class is used to mark where the special characters in the format
* are, as opposed to the other characters that are simply printed.
@ -166,8 +133,19 @@ namespace NPOI.SS.Format
* @param format The format to Parse.
*/
public CellNumberFormatter(String format)
: base(format)
: this(LocaleUtil.GetUserLocale(), format)
{
}
/**
* Creates a new cell number formatter.
*
* @param locale The locale to use.
* @param format The format to parse.
*/
public CellNumberFormatter(CultureInfo locale, String format)
: base(locale, format)
{
this.SIMPLE_NUMBER = new GeneralNumberFormatter(locale);
CellNumberPartHandler ph = new CellNumberPartHandler();
StringBuilder descBuf = CellFormatPart.ParseFormat(format, CellFormatType.NUMBER, ph);
@ -240,7 +218,7 @@ namespace NPOI.SS.Format
}
double[] scaleByRef = { ph.Scale };
integerCommas = interpretIntegerCommas(descBuf, specials, decimalPoint, integerEnd(), fractionalEnd(), scaleByRef);
showGroupingSeparator = interpretIntegerCommas(descBuf, specials, decimalPoint, integerEnd(), fractionalEnd(), scaleByRef);
if (exponent == null)
{
scale = scaleByRef[0];
@ -348,7 +326,7 @@ namespace NPOI.SS.Format
}
fmtBuf.Append('E');
placeZeros(fmtBuf, exponentSpecials.GetRange(2, exponentSpecials.Count - 2));
decimalFmt = new DecimalFormat(fmtBuf.ToString());
decimalFmt = new DecimalFormat(fmtBuf.ToString(), locale.NumberFormat);
printfFmt = null;
}
@ -356,6 +334,7 @@ namespace NPOI.SS.Format
desc = descBuf.ToString();
}
private static void placeZeros(StringBuilder sb, List<Special> specials)
{
foreach (Special s in specials)
@ -585,7 +564,7 @@ namespace NPOI.SS.Format
}
SortedList<CellNumberStringMod, object> mods = new SortedList<CellNumberStringMod, object>();
StringBuilder output = new StringBuilder(desc);
StringBuilder output = new StringBuilder(localiseFormat(desc));
if (exponent != null)
{
@ -598,13 +577,12 @@ namespace NPOI.SS.Format
else
{
StringBuilder result = new StringBuilder();
//Formatter f = new Formatter(result);
//f.Format(LOCALE, printfFmt, value);
result.Append(value.ToString(printfFmt));
result.Append(value.ToString(printfFmt, locale));
if (numerator == null)
{
WriteFractional(result, output);
Writeint(result, output, integerSpecials, mods, integerCommas);
Writeint(result, output, integerSpecials, mods, showGroupingSeparator);
}
else
{
@ -612,6 +590,8 @@ namespace NPOI.SS.Format
}
}
String groupingSeparator = locale.NumberFormat.NumberGroupSeparator;
// Now strip out any remaining '#'s and add any pending text ...
IEnumerator<Special> it = specials.GetEnumerator();//.ListIterator();
IEnumerator Changes = mods.Keys.GetEnumerator();
@ -636,7 +616,7 @@ namespace NPOI.SS.Format
{
case CellNumberStringMod.AFTER:
// ignore Adding a comma After a deleted char (which was a '#')
if (nextChange.ToAdd.Equals(",") && deletedChars.Get(s.pos))
if (nextChange.ToAdd.Equals(groupingSeparator) && deletedChars.Get(s.pos))
break;
output.Insert(modPos + 1, nextChange.ToAdd);
break;
@ -734,7 +714,7 @@ namespace NPOI.SS.Format
result.Append(value.ToString("E"));
}
Writeint(result, output, integerSpecials, mods, integerCommas);
Writeint(result, output, integerSpecials, mods, showGroupingSeparator);
WriteFractional(result, output);
/*
@ -903,6 +883,53 @@ namespace NPOI.SS.Format
//{
// return HasChar(ch, s1) || HasChar(ch, s2);
//}
private String localiseFormat(String format)
{
NumberFormatInfo dfs = locale.NumberFormat;
if (format.Contains(',') && dfs.NumberGroupSeparator != ",")
{
if (format.Contains('.') && dfs.NumberDecimalSeparator != ".")
{
format = ReplaceLast(format, ".", "[DECIMAL_SEPARATOR]");
format = format.Replace(",", dfs.NumberGroupSeparator)
.Replace("[DECIMAL_SEPARATOR]", dfs.NumberDecimalSeparator);
}
else
{
format = format.Replace(",", dfs.NumberGroupSeparator);
}
}
else if (format.Contains('.') && dfs.NumberDecimalSeparator != ".")
{
format = format.Replace(".", dfs.NumberDecimalSeparator);
}
return format;
}
public static string ReplaceLast(string input, string oldValue, string newValue)
{
int index = input.LastIndexOf(oldValue);
if (index < 0)
{
return input;
}
else
{
//StringBuilder sb = new StringBuilder(input.Length - oldValue.Length + newValue.Length);
//sb.Append(input.Substring(0, index));
//sb.Append(newValue);
//sb.Append(input.Substring(index + oldValue.Length,
// input.Length - index - oldValue.Length));
//return sb.ToString();
return input.Substring(0, index) + newValue
+ input.Substring(index + oldValue.Length, input.Length - index - oldValue.Length);
}
}
private static bool HasChar(char ch, params List<Special>[] numSpecials)
{
foreach (List<Special> specials in numSpecials)
@ -923,18 +950,20 @@ namespace NPOI.SS.Format
{
StringBuilder sb = new StringBuilder();
//Formatter formatter = new Formatter(sb);
//formatter.Format(LOCALE, fmt, num);
sb.Append(num.ToString(fmt));
sb.Append(num.ToString(fmt, locale));
Writeint(sb, output, numSpecials, mods, false);
}
private void Writeint(StringBuilder result, StringBuilder output,
List<Special> numSpecials, SortedList<CellNumberStringMod, object> mods,
bool ShowCommas)
bool showGroupingSeparator)
{
int pos = result.ToString().IndexOf('.') - 1;
NumberFormatInfo dfs = locale.NumberFormat;
String decimalSeparator = dfs.NumberDecimalSeparator;
String groupingSeparator = dfs.NumberGroupSeparator;
int pos = result.ToString().IndexOf(decimalSeparator) - 1;
if (pos < 0)
{
if (exponent != null && numSpecials == integerSpecials)
@ -947,12 +976,12 @@ namespace NPOI.SS.Format
for (strip = 0; strip < pos; strip++)
{
char resultCh = result[strip];
if (resultCh != '0' && resultCh != ',')
if (resultCh != '0' && resultCh != groupingSeparator[0])
break;
}
//ListIterator<Special> it = numSpecials.ListIterator(numSpecials.Count);
bool followWithComma = false;
bool followWithGroupingSeparator = false;
Special lastOutputintDigit = null;
int digit = 0;
//while (it.HasPrevious()) {
@ -967,7 +996,7 @@ namespace NPOI.SS.Format
resultCh = '0';
}
Special s = numSpecials[i];
followWithComma = ShowCommas && digit > 0 && digit % 3 == 0;
followWithGroupingSeparator = showGroupingSeparator && digit > 0 && digit % 3 == 0;
bool zeroStrip = false;
if (resultCh != '0' || s.ch == '0' || s.ch == '?' || pos >= strip)
{
@ -975,10 +1004,10 @@ namespace NPOI.SS.Format
output[s.pos] = (zeroStrip ? ' ' : resultCh);
lastOutputintDigit = s;
}
if (followWithComma)
if (followWithGroupingSeparator)
{
mods.Add(insertMod(s, zeroStrip ? " " : ",", CellNumberStringMod.AFTER), null);
followWithComma = false;
mods.Add(insertMod(s, zeroStrip ? " " : groupingSeparator, CellNumberStringMod.AFTER), null);
followWithGroupingSeparator = false;
}
digit++;
--pos;
@ -990,12 +1019,12 @@ namespace NPOI.SS.Format
// pos was decremented at the end of the loop above when the iterator was at its end
++pos;
extraLeadingDigits = new StringBuilder(result.ToString().Substring(0, pos));
if (ShowCommas)
if (showGroupingSeparator)
{
while (pos > 0)
{
if (digit > 0 && digit % 3 == 0)
extraLeadingDigits.Insert(pos, ',');
extraLeadingDigits.Insert(pos, groupingSeparator);
digit++;
--pos;
}
@ -1011,7 +1040,8 @@ namespace NPOI.SS.Format
if (fractionalSpecials.Count > 0)
{
string resultString = result.ToString();
digit = resultString.IndexOf('.') + 1;
String decimalSeparator = locale.NumberFormat.NumberDecimalSeparator;
digit = resultString.IndexOf(decimalSeparator) + 1;
if (exponent != null)
strip = resultString.IndexOf('E') - 1;
else

26
main/SS/UserModel/DataFormatter.cs

@ -178,7 +178,7 @@ namespace NPOI.SS.UserModel
/** A default FormatBase to use when a number pattern cannot be Parsed. */
private FormatBase defaultNumFormat;
private CultureInfo currentCulture;
private CultureInfo locale;
/*
* A map to cache formats.
@ -247,7 +247,7 @@ namespace NPOI.SS.UserModel
public DataFormatter(CultureInfo culture, bool localeIsAdapting, bool emulateCSV)
{
this.localeIsAdapting = true;
this.currentCulture = culture;
this.locale = culture;
//localeChangedObservable.addObserver(this);
// localeIsAdapting must be true prior to this first checkForLocaleChange call.
//localeChangedObservable.checkForLocaleChange(culture);
@ -297,12 +297,6 @@ namespace NPOI.SS.UserModel
* @param cell The cell to retrieve a FormatBase for
* @return A FormatBase for the FormatBase String
*/
private FormatBase GetFormat(ICell cell)
{
return GetFormat(cell, null);
}
private FormatBase GetFormat(ICell cell, ConditionalFormattingEvaluator cfEvaluator)
{
if (cell == null) return null;
@ -346,7 +340,7 @@ namespace NPOI.SS.UserModel
try
{
// Ask CellFormat to get a formatter for it
CellFormat cfmt = CellFormat.GetInstance(formatStr);
CellFormat cfmt = CellFormat.GetInstance(locale, formatStr);
// CellFormat requires callers to identify date vs not, so do so
object cellValueO = (cellValue);
if (DateUtil.IsADateFormat(formatIndex, formatStr) &&
@ -714,7 +708,7 @@ namespace NPOI.SS.UserModel
try
{
//return new SimpleDateFormat(formatStr);
return new ExcelStyleDateFormatter(formatStr);
return new ExcelStyleDateFormatter(formatStr, dateSymbols);
}
catch (ArgumentException)
{
@ -838,7 +832,7 @@ namespace NPOI.SS.UserModel
// correct grouping for non-US locales.
if (grouping != ',')
{
symbols = currentCulture.NumberFormat.Clone() as NumberFormatInfo;
symbols = locale.NumberFormat.Clone() as NumberFormatInfo;
symbols.NumberGroupSeparator = grouping.ToString();
string oldPart = agm.Groups[1].Value;
string newPart = oldPart.Replace(grouping, ',');
@ -930,7 +924,7 @@ namespace NPOI.SS.UserModel
double d = cell.NumericCellValue;
if (numberFormat == null)
{
return d.ToString(currentCulture);
return d.ToString(locale);
}
//return numberFormat.Format(d, currentCulture);
string formatted = numberFormat.Format(d);
@ -997,7 +991,7 @@ namespace NPOI.SS.UserModel
FormatBase numberFormat = GetFormat(value, formatIndex, formatString);
if (numberFormat == null)
{
return value.ToString(currentCulture);
return value.ToString(locale);
}
// When formatting 'value', double to text to BigDecimal produces more
// accurate results than double to Double in JDK8 (as compared to
@ -1206,13 +1200,13 @@ namespace NPOI.SS.UserModel
public void Update(IObservable<object> observable, object localeObj)
{
if (localeObj is not CultureInfo newLocale) return;
if (newLocale.Equals(currentCulture)) return;
if (newLocale.Equals(locale)) return;
currentCulture = newLocale;
locale = newLocale;
//dateSymbols = DateFormatSymbols.getInstance(currentCulture);
//decimalSymbols = DecimalFormatSymbols.getInstance(currentCulture);
generalNumberFormat = new ExcelGeneralNumberFormat(currentCulture);
generalNumberFormat = new ExcelGeneralNumberFormat(locale);
// init built-in formats

21
testcases/main/SS/UserModel/TestDataFormatter.cs

@ -868,18 +868,15 @@ namespace TestCases.SS.UserModel
public void TestBug60422()
{
//LocaleUtil.setUserLocale(Locale.ROOT);
try
{
char euro = '\u20AC';
DataFormatter df = new DataFormatter(CultureInfo.GetCultureInfo("de-DE"));
String formatString = String.Format("_-* #,##0.00\\ \"{0}\"_-;\\-* #,##0.00\\ \"{1}\"_-;_-* \"-\"??\\ \"{2}\"_-;_-@_-",
euro, euro, euro);
ClassicAssert.AreEqual("4.33 " + euro, df.FormatRawCellContents(4.33, 178, formatString));
}
finally
{
//LocaleUtil.resetUserLocale();
}
char euro = '\u20AC';
DataFormatter df = new DataFormatter(CultureInfo.GetCultureInfo("de-DE"));
String formatString = String.Format("_-* #,##0.00\\ \"{0}\"_-;\\-* #,##0.00\\ \"{1}\"_-;_-* \"-\"??\\ \"{2}\"_-;_-@_-",
euro, euro, euro);
ClassicAssert.AreEqual("4,33 " + euro, df.FormatRawCellContents(4.33, 178, formatString));
ClassicAssert.AreEqual("1.234,33 " + euro, df.FormatRawCellContents(1234.33, 178, formatString));
}
}
}
Loading…
Cancel
Save