Reading the same Asta .pp file under different default locales produces different task data. Reproduced on 16.7.0 using only the public API:
locale=en-US tasks=10344 actualFinish=1593 critical=1057
locale=en-AU tasks=10344 actualFinish=460 critical=2190
locale=de-DE tasks=10344 actualFinish=460 critical=2190
Same bytes, same library, three answers. Scheduled dates are unaffected — across all 10,344 tasks start, finish, early_start and actual_start are identical under every locale. What changes is actual_finish, which the affected locales leave null where the correct parse sets it; early_finish, late_finish and critical follow from that.
Cause
org.mpxj.asta.DatatypeConverter.parseDouble routes any value containing an exponent through a ThreadLocal<DecimalFormat> built as:
new DecimalFormat("#.#E0")
No Locale argument, so it takes the JVM default's DecimalFormatSymbols. Where those do not match the file's ASCII 1.0E9 notation, DecimalFormat.parse stops at the first character it cannot read and returns the mantissa without throwing:
Locale.setDefault(Locale.forLanguageTag("en-AU"));
new DecimalFormat("#.#E0").parse("1.0E9"); // returns 1
Double.valueOf("1.0E9"); // 1.0E9
en-AU and en-CA use a lowercase e as the exponent separator; fr/de/es use a comma decimal separator; ar-EG uses اس. Measured against Double.valueOf as ground truth:
| locale |
exponent symbol |
1.0E9 parses as |
correct |
| en-US, en-GB, en-NZ, en-IN |
E |
1000000000 |
yes |
| en-AU, en-CA |
e |
1 |
no |
| fr-FR, de-DE, es-ES |
E |
1 |
no (comma decimal) |
| ar-EG |
اس |
1 |
no |
The non-exponent path already uses locale-independent Double.valueOf, so the two branches disagree.
Suggested fix
new DecimalFormat("#.#E0", DecimalFormatSymbols.getInstance(Locale.ROOT))
Notes
Found while investigating why the same schedule produced different critical-path counts on a developer machine and a server. Our workaround is to pin the JVM locale before reading.
I have not identified which Asta fields carry exponent notation — only that the path is exercised and the outputs diverge. Happy to supply a sample file privately if that would help; the one used here is client-confidential so I would rather not attach it publicly.
Reading the same Asta
.ppfile under different default locales produces different task data. Reproduced on 16.7.0 using only the public API:Same bytes, same library, three answers. Scheduled dates are unaffected — across all 10,344 tasks
start,finish,early_startandactual_startare identical under every locale. What changes isactual_finish, which the affected locales leave null where the correct parse sets it;early_finish,late_finishandcriticalfollow from that.Cause
org.mpxj.asta.DatatypeConverter.parseDoubleroutes any value containing an exponent through aThreadLocal<DecimalFormat>built as:No
Localeargument, so it takes the JVM default'sDecimalFormatSymbols. Where those do not match the file's ASCII1.0E9notation,DecimalFormat.parsestops at the first character it cannot read and returns the mantissa without throwing:en-AUanden-CAuse a lowercaseeas the exponent separator;fr/de/esuse a comma decimal separator;ar-EGusesاس. Measured againstDouble.valueOfas ground truth:1.0E9parses asEeEاسThe non-exponent path already uses locale-independent
Double.valueOf, so the two branches disagree.Suggested fix
Notes
Found while investigating why the same schedule produced different critical-path counts on a developer machine and a server. Our workaround is to pin the JVM locale before reading.
I have not identified which Asta fields carry exponent notation — only that the path is exercised and the outputs diverge. Happy to supply a sample file privately if that would help; the one used here is client-confidential so I would rather not attach it publicly.