Как напечатать знак года в DateTimeFormatter, когда количество букв четыре?

Из DateTimeFormatter javadoc:

Если количество букв меньше четырех (но не двух), то знак выводится только для отрицательных лет согласно SignStyle.NORMAL. В противном случае знак выводится, если ширина контактной площадки превышена, согласно SignStyle.EXCEEDS_PAD.

Насколько я понимаю, если ширина панели не превышена и количество букв равно четырем, знак минус (для отрицательных лет) не должен печататься во время форматирования.

Поэтому я написал такой фрагмент кода (полагая, что не могу использовать 'y'потому что тогда год всегда будет положительным):

    var negativeDate = LocalDate.now().minus(2021, ChronoUnit.YEARS);
    var formatter = DateTimeFormatter.ofPattern("ppppuuuu");
    var text = negativeDate.format(formatter);
    System.out.println("formatted string: " + text);

Этот код бросает DateTimeException: "Невозможно напечатать, поскольку вывод 5 символов превышает ширину блока 4".

Итак, мой вопрос в основном заключается в том, как увидеть это последнее предложение из работы javadoc.

3 ответа

Решение

В противном случае в предложении вы спрашиваете о относится к ситуации, когда подсчет букв 4 или больше. Как ни странно, ширина пэда здесь не имеет ничего общего с буквой узора. pдля набивки. Это относится к количеству печатаемых цифр. Это относится к первому предложению абзаца . Количество букв определяет минимальную ширину поля, ниже которой используется заполнение.

Итак, чтобы убедиться в этом, используйте 4 или более шаблонных букв и используйте год, который состоит из большего количества цифр, чем количество шаблонных букв. Работает как с u, y и Y.

    DateTimeFormatter uuuu = DateTimeFormatter.ofPattern("uuuu");
    DateTimeFormatter yyyy = DateTimeFormatter.ofPattern("yyyy");
    DateTimeFormatter uppercaseYyyy = DateTimeFormatter.ofPattern("YYYY");
    
    LocalDate ld = LocalDate.of(12345, Month.OCTOBER, 23);
    
    System.out.println(ld.format(uuuu));
    System.out.println(ld.format(yyyy));
    System.out.println(ld.format(uppercaseYyyy));

Вывод:

+12345
+12345
+12345

Знак минус печатается независимо от количества печатаемых символов. Документация SignStyle.EXCEEDS_PAD говорит:

… Отрицательное значение всегда будет выводить знак "-".

Ссылка на документацию: SignStyle.EXCEEDS_PAD

Этот образец "ppppuuuu" определяет padWidth из 4 применено к следующему формату uuuu, который применяется SignStyle.EXCEEDS_PAD(согласно javadoc для DateTimeFormatBuilder).

Это - всегда печатается из-за текущего SignStyle.

Таким образом, когда форматтер пытается напечатать год с отрицательным знаком, он использует 4 цифры и знак, таким образом превышая доступный padWidth.

Точно так же знак всегда печатается при использовании u или же uuu шаблоны, потому что SignStyle.NORMAL применяется в этих случаях.

Таким образом, знак не будет напечатан только тогда, когда uu формат используется.

Чтобы избежать исключения для отрицательного числа, заполнение должно превышать количество цифр, например, "ppppu" или же "pppppuuuu".

var onlyU = DateTimeFormatter.ofPattern("uuuu");
var padded = DateTimeFormatter.ofPattern("ppppu");
var padded5 = DateTimeFormatter.ofPattern("pppppuuuu");

for (LocalDate d = LocalDate.now().minus(2421, ChronoUnit.YEARS); d.getYear() < 2200; d = d.plus(400, ChronoUnit.YEARS)) {

    try {
        var uuuu  = d.format(onlyU);
        var ppppu = d.format(padded);
        var pppppuuuu = d.format(padded5);

        System.out.printf("formatted year=%5d\tuuuu=[%s] \tppppu=[%s]\tpppppuuuu=[%s]%n", d.getYear(), uuuu, ppppu, pppppuuuu);

    } catch (DateTimeException e) {
        System.out.println("error: " + e);  
    }
}

Вывод:

formatted year= -401    uuuu=[-0401]    ppppu=[-401]    pppppuuuu=[-0401]
formatted year=   -1    uuuu=[-0001]    ppppu=[  -1]    pppppuuuu=[-0001]
formatted year=  399    uuuu=[0399]     ppppu=[ 399]    pppppuuuu=[ 0399]
formatted year=  799    uuuu=[0799]     ppppu=[ 799]    pppppuuuu=[ 0799]
formatted year= 1199    uuuu=[1199]     ppppu=[1199]    pppppuuuu=[ 1199]
formatted year= 1599    uuuu=[1599]     ppppu=[1599]    pppppuuuu=[ 1599]
formatted year= 1999    uuuu=[1999]     ppppu=[1999]    pppppuuuu=[ 1999]

Если количество букв меньше четырех (но не двух), то знак выводится только для отрицательных лет согласно SignStyle.NORMAL.

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class Main {
    public static void main(String[] args) {
        var negativeDate = LocalDate.now().minus(2021, ChronoUnit.YEARS);
        var formatter1 = DateTimeFormatter.ofPattern("ppuu");
        var formatter2 = DateTimeFormatter.ofPattern("ppu");
        var text1 = negativeDate.format(formatter1);
        var text2 = negativeDate.format(formatter2);
        System.out.println("formatted string: year" + text1);
        System.out.println("formatted string: year" + text2);
    }
}

Вывод:

formatted string: year01
formatted string: year-1

я использовал uu (количество букв как два) в formatter1и поэтому не имеет отрицательного знака. Однако, если количество букв меньше четырех, а не двух, вам необходимо предоставить достаточное количество отступов, например, для года, -1, вам нужно заполнить как минимум 2 (т.е. pp), один для - знак и один для 1. Если вы предоставите меньшее количество отступов, вы получите DateTimeException и если вы предоставите больше, чем 2 обивка, вы получите место перед -1.

Таким образом, в случае формата uuuu, вам нужен отступ не менее 5 (т.е. ppppp) за отрицательный год, один за - и 4 годами (0001) т.е. вам нужно использовать DateTimeFormatter.ofPattern("pppppuuuu") избежать DateTimeException.

Другие вопросы по тегам