Skip to content

Commit

Permalink
better format support and documentation
Browse files Browse the repository at this point in the history
see issue #615
  • Loading branch information
MenoData committed Jul 24, 2017
1 parent ef0617f commit 014be7b
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,69 @@
*
* <p>Furthermore, all elements defined in {@code EpochDays} are supported. </p>
*
* <p><strong>Formatting and parsing:</strong> When using format patterns the
* {@link net.time4j.format.expert.PatternType#DYNAMIC dynamic pattern type}
* is strongly recommended instead of CLDR-like pattern types because this calendar
* is structurally different from month-based calendars. Following symbol-element
* table holds: </p>
*
* <div style="margin-top:5px;">
* <table border="1">
* <caption>Mapping of dynamic pattern symbols</caption>
* <tr>
* <th>element</th><th>symbol</th><th>type</th>
* </tr>
* <tr>
* <td>ERA</td><td>G</td><td>text</td>
* </tr>
* <tr>
* <td>YEAR_OF_ERA</td><td>Y</td><td>number</td>
* </tr>
* <tr>
* <td>MONTH_OF_YEAR</td><td>M</td><td>text</td>
* </tr>
* <tr>
* <td>SANSCULOTTIDES</td><td>S</td><td>text</td>
* </tr>
* <tr>
* <td>DAY_OF_MONTH</td><td>D</td><td>number</td>
* </tr>
* <tr>
* <td>DAY_OF_DECADE</td><td>C</td><td>text</td>
* </tr>
* <tr>
* <td>DAY_OF_WEEK</td><td>E</td><td>text</td>
* </tr>
* </table>
* </div>
*
* <p>Note: The standalone form of some enums like the republican month can be printed in a capitalized way
* if the formatter is first constructed on builder level by using a sectional attribute for the output context.
* Alternatively, users can simply modify the formatter by calling
* {@code f.with(Attributes.OUTPUT_CONTEXT, OutputContext.STANDALONE)}. </p>
*
* <p>Furthermore: The abbreviated form of the republican month is usually numeric with two arabic digits. For
* more control about the numeric representation, the builder offers extra fine-tuned methods. </p>
*
* <p>It is strongly recommended to use the or-operator &quot;|&quot; in format patterns because not every date of
* this calendar has a month. Example: </p>
*
* <pre>
* ChronoFormatter&lt;FrenchRepublicanCalendar&gt; f =
* ChronoFormatter
* .setUp(FrenchRepublicanCalendar.axis(), Locale.FRENCH)
* .startSection(Attributes.NUMBER_SYSTEM, NumberSystem.ARABIC)
* .addPattern(&quot;[D. MMMM|SSSS]&#39;, an &#39;Y&quot;, PatternType.DYNAMIC)
* .endSection()
* .build();
*
* FrenchRepublicanCalendar cal = PlainDate.of(2018, 9, 23).transform(FrenchRepublicanCalendar.axis());
* System.out.println(f.format(cal)); // output =&gt; 1. vendémiaire, an 227
*
* cal = cal.minus(CalendarDays.ONE);
* System.out.println(f.format(cal)); // output =&gt; jour de la révolution, an 226
* </pre>
*
* @author Meno Hochschild
* @see FrenchRepublicanEra
* @see FrenchRepublicanMonth
Expand Down Expand Up @@ -158,6 +221,69 @@
*
* <p>Au&slig;erdem werden alle Elemente von {@code EpochDays} unterst&uuml;tzt. </p>
*
* <p><strong>Formatieren und Interpretation:</strong> Wenn Formatmuster verwendet werden,
* wird der {@link net.time4j.format.expert.PatternType#DYNAMIC dynamische Formatmustertyp}
* anstelle von CLDR-basierten Formatmustertypen empfohlen, weil dieser Kalender strukturell
* von monatsbasierten Kalendern verschieden ist. Folgende Symbol-Element-Tabelle gilt: </p>
*
* <div style="margin-top:5px;">
* <table border="1">
* <caption>Zuordnung von dynamischen Mustersymbolen</caption>
* <tr>
* <th>element</th><th>symbol</th><th>type</th>
* </tr>
* <tr>
* <td>ERA</td><td>G</td><td>text</td>
* </tr>
* <tr>
* <td>YEAR_OF_ERA</td><td>Y</td><td>number</td>
* </tr>
* <tr>
* <td>MONTH_OF_YEAR</td><td>M</td><td>text</td>
* </tr>
* <tr>
* <td>SANSCULOTTIDES</td><td>S</td><td>text</td>
* </tr>
* <tr>
* <td>DAY_OF_MONTH</td><td>D</td><td>number</td>
* </tr>
* <tr>
* <td>DAY_OF_DECADE</td><td>C</td><td>text</td>
* </tr>
* <tr>
* <td>DAY_OF_WEEK</td><td>E</td><td>text</td>
* </tr>
* </table>
* </div>
*
* <p>Hinweis: Die <i>standalone</i>-Form einiger Enums wie dem republikanischen Monat ist in einer
* kapitalisierten Weise erh&auml;ltlich, wenn der Formatierer zuerst mittels seines <i>builder</i>
* konstruiert und ein sektionales Attribut f&uuml;r den Ausgabekontext verwendet wird. Alternativ
* kann man am Formatierer {@code f.with(Attributes.OUTPUT_CONTEXT, OutputContext.STANDALONE)} aufrufen. </p>
*
* <p>Au&szlig;erdem ist die abgek&uuml;rzte Schreibweise des republikanischen Monats gew&ouml;hnlich
* numerisch mit zwei arabischen Ziffern. Um mehr Kontrolle &uuml;ber die numerische Repr&auml;sentation
* zu bekommen, bietet der <i>builder</i> weitere feingranulare Methoden an. </p>
*
* <p>Weil nicht jedes Datum dieses Kalenders einen Monat hat, ist es angeraten, mit dem Oder-Operator
* &quot;|&quot; in der Formatierung zu arbeiten. Beispiel: </p>
*
* <pre>
* ChronoFormatter&lt;FrenchRepublicanCalendar&gt; f =
* ChronoFormatter
* .setUp(FrenchRepublicanCalendar.axis(), Locale.FRENCH)
* .startSection(Attributes.NUMBER_SYSTEM, NumberSystem.ARABIC)
* .addPattern(&quot;[D. MMMM|SSSS]&#39;, an &#39;Y&quot;, PatternType.DYNAMIC)
* .endSection()
* .build();
*
* FrenchRepublicanCalendar cal = PlainDate.of(2018, 9, 23).transform(FrenchRepublicanCalendar.axis());
* System.out.println(f.format(cal)); // Ausgabe =&gt; 1. vendémiaire, an 227
*
* cal = cal.minus(CalendarDays.ONE);
* System.out.println(f.format(cal)); // Ausgabe =&gt; jour de la révolution, an 226
* </pre>
*
* @author Meno Hochschild
* @see FrenchRepublicanEra
* @see FrenchRepublicanMonth
Expand Down Expand Up @@ -196,14 +322,14 @@ public final class FrenchRepublicanCalendar
/*[deutsch]
* <p>Repr&auml;sentiert das republikanische Jahr gez&auml;hlt seit 1792-09-22 (im Bereich 1-1202). </p>
*/
@FormattableElement(format = "y")
@FormattableElement(format = "Y")
public static final StdCalendarElement<Integer, FrenchRepublicanCalendar> YEAR_OF_ERA =
new StdIntegerDateElement<>(
"YEAR_OF_ERA",
FrenchRepublicanCalendar.class,
1,
MAX_YEAR,
'y',
'Y',
null,
null);

Expand Down Expand Up @@ -238,6 +364,7 @@ public final class FrenchRepublicanCalendar
* @see #hasSansculottides()
* @see #hasMonth()
*/
@FormattableElement(format = "S")
public static final ChronoElement<Sansculottides> SANSCULOTTIDES = SANSCULOTTIDES_ACCESS;

/**
Expand Down Expand Up @@ -324,6 +451,7 @@ public final class FrenchRepublicanCalendar
* @see #hasSansculottides()
* @see #hasMonth()
*/
@FormattableElement(format = "C")
public static final ChronoElement<DayOfDecade> DAY_OF_DECADE = DAY_OF_DECADE_ACCESS;

/**
Expand All @@ -348,19 +476,18 @@ public final class FrenchRepublicanCalendar
* @see #hasSansculottides()
* @see #hasMonth()
*/
@FormattableElement(format = "d")
@FormattableElement(format = "D")
public static final StdCalendarElement<Integer, FrenchRepublicanCalendar> DAY_OF_MONTH =
new StdIntegerDateElement<>("DAY_OF_MONTH", FrenchRepublicanCalendar.class, 1, 30, 'd');
new StdIntegerDateElement<>("DAY_OF_MONTH", FrenchRepublicanCalendar.class, 1, 30, 'D');

/**
* <p>Represents the day of year. </p>
*/
/*[deutsch]
* <p>Repr&auml;sentiert den Tag des Jahres. </p>
*/
@FormattableElement(format = "D")
public static final StdCalendarElement<Integer, FrenchRepublicanCalendar> DAY_OF_YEAR =
new StdIntegerDateElement<>("DAY_OF_YEAR", FrenchRepublicanCalendar.class, 1, 365, 'D');
new StdIntegerDateElement<>("DAY_OF_YEAR", FrenchRepublicanCalendar.class, 1, 365, '\u0000');

/**
* <p>Represents the day of week where the week is seven days long. </p>
Expand Down Expand Up @@ -1838,6 +1965,13 @@ private static class DayOfDecadeAccess

//~ Methoden ------------------------------------------------------

@Override
public char getSymbol() {

return 'C';

}

@Override
public DayOfDecade getValue(FrenchRepublicanCalendar context) {

Expand Down Expand Up @@ -2008,6 +2142,13 @@ private static class SansculottidesAccess

//~ Methoden ------------------------------------------------------

@Override
public char getSymbol() {

return 'S';

}

@Override
public Sansculottides getValue(FrenchRepublicanCalendar context) {

Expand Down
13 changes: 13 additions & 0 deletions calendar/src/main/resources/names/extra/frenchrev.properties
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ M(w)_10=10
M(w)_11=11
M(w)_12=12

M(a)_1=01
M(a)_2=02
M(a)_3=03
M(a)_4=04
M(a)_5=05
M(a)_6=06
M(a)_7=07
M(a)_8=08
M(a)_9=09
M(a)_10=10
M(a)_11=11
M(a)_12=12

M(N)_1=1
M(N)_2=2
M(N)_3=3
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package net.time4j.calendar.frenchrev;

import net.time4j.PlainDate;
import net.time4j.engine.CalendarDays;
import net.time4j.format.Attributes;
import net.time4j.format.NumberSystem;
import net.time4j.format.expert.ChronoFormatter;
import net.time4j.format.expert.PatternType;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.text.ParseException;
import java.util.Locale;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;


@RunWith(JUnit4.class)
public class FormatTest {

@Test
public void printMonthOrSansculottidesOnGroundLevel() {
ChronoFormatter<FrenchRepublicanCalendar> f = create("D MMMM' an 'Y|SSSS', an 'Y");
FrenchRepublicanCalendar cal = PlainDate.of(2018, 9, 23).transform(FrenchRepublicanCalendar.axis());
assertThat(
f.format(cal),
is("1 vendémiaire an 227"));
assertThat(
f.format(cal.minus(CalendarDays.ONE)),
is("jour de la révolution, an 226"));
}

@Test
public void printMonthOrSansculottidesInsideOptionalSection() {
ChronoFormatter<FrenchRepublicanCalendar> f = create("[D MMMM|SSSS]', an 'Y");
FrenchRepublicanCalendar cal = PlainDate.of(2018, 9, 23).transform(FrenchRepublicanCalendar.axis());
assertThat(
f.format(cal),
is("1 vendémiaire, an 227"));
assertThat(
f.format(cal.minus(CalendarDays.ONE)),
is("jour de la révolution, an 226"));
}

@Test
public void parseMonthOrSansculottides() throws ParseException {
ChronoFormatter<FrenchRepublicanCalendar> f = create("D MMMM' an 'Y|SSSS', an 'Y");
FrenchRepublicanCalendar cal = PlainDate.of(2018, 9, 23).transform(FrenchRepublicanCalendar.axis());
assertThat(
f.parse("1 vendémiaire an 227"),
is(cal));
assertThat(
f.parse("jour de la révolution, an 226"),
is(cal.minus(CalendarDays.ONE)));
}

@Test
public void printWithSpecificAlgorithm() {
ChronoFormatter<FrenchRepublicanCalendar> f = create("YYYY-MM-DD");
FrenchRepublicanCalendar cal = PlainDate.of(2018, 9, 23).transform(FrenchRepublicanCalendar.axis());
assertThat(
f.format(cal),
is("0227-01-01"));
assertThat(
f.with(FrenchRepublicanAlgorithm.attribute(), FrenchRepublicanAlgorithm.EQUINOX).format(cal),
is("0227-01-01"));
assertThat(
f.with(FrenchRepublicanAlgorithm.attribute(), FrenchRepublicanAlgorithm.ROMME).format(cal),
is("0227-01-02"));
}

@Test
public void parseWithSpecificAlgorithm() throws ParseException {
ChronoFormatter<FrenchRepublicanCalendar> f = create("YYYY-MM-DD");
FrenchRepublicanCalendar cal = PlainDate.of(2018, 9, 23).transform(FrenchRepublicanCalendar.axis());
assertThat(
f.parse("0227-01-01"),
is(cal));
assertThat(
f.with(FrenchRepublicanAlgorithm.attribute(), FrenchRepublicanAlgorithm.EQUINOX).parse("0227-01-01"),
is(cal));
assertThat(
f.with(FrenchRepublicanAlgorithm.attribute(), FrenchRepublicanAlgorithm.ROMME).parse("0227-01-02"),
is(cal));
}

private static ChronoFormatter<FrenchRepublicanCalendar> create(String pattern) {
return ChronoFormatter
.setUp(FrenchRepublicanCalendar.axis(), Locale.FRENCH)
.startSection(Attributes.NUMBER_SYSTEM, NumberSystem.ARABIC)
.addPattern(pattern, PatternType.DYNAMIC)
.endSection()
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void dayOfMonth() {
is(true));
assertThat(
FrenchRepublicanCalendar.DAY_OF_MONTH.getSymbol(),
is('d'));
is('D'));
assertThat(
FrenchRepublicanCalendar.DAY_OF_MONTH.isDateElement(),
is(true));
Expand Down Expand Up @@ -119,7 +119,7 @@ public void dayOfDecade() {
is(true));
assertThat(
FrenchRepublicanCalendar.DAY_OF_DECADE.getSymbol(),
is('\u0000'));
is('C'));
assertThat(
FrenchRepublicanCalendar.DAY_OF_DECADE.isDateElement(),
is(true));
Expand Down Expand Up @@ -276,7 +276,7 @@ public void dayOfYear() {
is(true));
assertThat(
FrenchRepublicanCalendar.DAY_OF_YEAR.getSymbol(),
is('D'));
is('\u0000'));
assertThat(
FrenchRepublicanCalendar.DAY_OF_YEAR.isDateElement(),
is(true));
Expand Down Expand Up @@ -598,7 +598,7 @@ public void yearOfEra() {
is(true));
assertThat(
FrenchRepublicanCalendar.YEAR_OF_ERA.getSymbol(),
is('y'));
is('Y'));
assertThat(
FrenchRepublicanCalendar.YEAR_OF_ERA.isDateElement(),
is(true));
Expand Down Expand Up @@ -685,7 +685,7 @@ public void sansculottides() {
is(true));
assertThat(
FrenchRepublicanCalendar.SANSCULOTTIDES.getSymbol(),
is('\u0000'));
is('S'));
assertThat(
FrenchRepublicanCalendar.SANSCULOTTIDES.isDateElement(),
is(true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@SuiteClasses(
{
DayOfDecadeTest.class,
FormatTest.class,
FrenchRepublicanCalendarTest.class,
FrenchRepublicanElementTest.class,
FrenchRepublicanEraTest.class,
Expand Down

0 comments on commit 014be7b

Please sign in to comment.