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

#java #datetime-format #java-time #datetimeformatter

#java #datetime-формат #java-время #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.

Ответ №1:

Иначе в предложении, о котором вы спрашиваете, относится к ситуации, когда количество букв равно 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

Ответ №2:

Если количество букв меньше четырех (но не двух), то знак выводится только для отрицательных лет в соответствии с 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 .

Комментарии:

1. это не отвечает на мой вопрос («как увидеть это последнее предложение из работы javadoc») — так что случай «в противном случае» с 4 буквами

Ответ №3:

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

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

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

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

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

Чтобы избежать исключения для отрицательного числа, заполнение должно превышать количество цифр, например, "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=]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]
  

Комментарии:

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

2. Извините, мой ответ прекрасно объясняет причину использования формата DateTimeException when ppppuuuu из-за применения SignStyle.EXCEED_PAD . Принятый в настоящее время ответ не содержит никаких шаблонов с заполнением. Неважно…

3. да! но, пожалуйста, подумайте, каков был мой первоначальный вопрос! Я начал играть с этим p в шаблоне только потому, что неправильно понял объяснение из последнего цитируемого предложения . Я ценю ваши усилия, просто это не то, что я искал — и это было настолько сложно для меня, что я даже забыл, что я имел в виду изначально 🙂 только этот сегодняшний ответ напомнил мне. может быть, кто-то еще найдет это полезным. приветствия