averbraeck / djutils

Delft Java Utilities for statistics, stochastics, data analysis and serialization
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

CliUtil default decimal values and Locale #13

Open WJSchakel opened 1 year ago

WJSchakel commented 1 year ago

Suppose a class (program) has the following command line argument:

    @Option(names = "--acceptedGap", description = "Accepted gap.", defaultValue = "0.5s")
    private Duration acceptedGap;

The resulting value (when no command line argument is given and hence the default value should be used) will actually depend on the Locale. In particular:

Locale.setDefault(Locale.Category.FORMAT, Locale.US); results in 0.5s. Locale.setDefault(Locale.Category.FORMAT, Locale.GERMAN); results in 5.0s. When System.out.println(Locale.getDefault(Locale.Category.FORMAT)); prints nl_NL, this results in 5.0s. Although Locale.setDefault(Locale.Category.FORMAT, new Locale("nl_NL")); results in 0.5s. Locale.setDefault(Locale.Category.FORMAT, Locale.FRANCE); results in 0.0s.

This issue can be circumvented by using:

    @Option(names = "--acceptedGap", description = "Accepted gap.")
    private Duration acceptedGap = Duration.instantiateSI(0.5);

But this form of using default values has limitations elsewhere.

This issue only occurs with DJNUITS properties. For e.g. a double the default value works fine.

WJSchakel commented 3 months ago

I see two options to solve this issue:

1) Force use of Locale.US for default values. DJUNITS does not support this directly in the valueOf(String) methods, but that will use a NumberFormat which uses Locale.getDefault(Locale.Category.FORMAT). Therefore, CliUtil could set Locale.setDefault(Locale.Category.FORMAT, Locale.US); in the execute() method just before the line ParseResult parseResult = commandLine.parseArgs(args);. It must also reset the value.

2) Forward a Locale to the CliUtil.execute() method, and use it in the same way.

In theory, other code could change the Locale during the call to parseArgs(). But the scope of this code is limited and involves custom converters found in CliUnitConverters.