当前位置: 首页 > 知识库问答 >
问题:

java的Vaadin流渲染器。超过LocalDateTime的时间日期时间类型

秦凯旋
2023-03-14

在Vaadin Flow版本14.1中,我发现只有两种日期时间类型的渲染器实现:

  • 本地日期渲染器

第一个是针对LocalDate类中的仅日期值,没有一天中的时间和时区。这很好。

第二个是用于表示日期和时间的类,但故意缺少时区上下文或UTC偏移量。很好。

问题是我找不到其他几个java的渲染器。时间数据类型。这是我用各种日期时间类型制作的图表,现代java。时间类型,以及它们替代的旧日期时间类,以及SQL标准等效数据类型的列表。

具体而言,在商业应用程序中,我们倾向于使用LocalDateTime的频率较低,主要用于预订未来的约会,因为政客可以更改时区的定义(世界各地的政客都经常这样做)。LocalDateTime类不能代表一个时刻。例如,以今年1月23日下午3点为例。如果没有时区或UTC的偏移量,我们不知道这是否意味着日本东京下午3点、法国图卢兹下午3点或美国俄亥俄州托莱多下午3点——三个截然不同的时刻相隔数小时。

为了表示一个时刻,我们必须使用Instant、OffsetDateTime或ZonedDateTime类。瞬间是UTC中的一个时刻,根据定义总是UTC中的一个时刻。偏移日期时间(OffsetDateTime)表示从UTC偏移数小时分秒的时刻。分区DateTime是一个特定地区(时区)的人们通过墙上的时钟看到的时刻。此类时区是该区域中使用的偏移的过去、现在和未来变化的历史。

➥ Vaadin 14是否为其他类型的渲染器提供渲染器?如果没有,是否有解决方法或制作渲染器的方法

共有1个答案

梁丘俊材
2023-03-14

您可以轻松创建自己的渲染器实现。

下面是我编写的渲染器,用于处理网格小部件,显示包含即时对象的对象。瞬间是一个时刻,是时间线上的一个特定点,如UTC所示(零小时分秒的偏移量)。Instant类是java中使用的基本构建块类。时间框架。

这里的想法是我们取Instant对象,应用指定的ZoneId来获取ZonedDateTime对象。该ZonedDateTime对象使用指定的DateTimeForey对象在String对象中生成文本。文本表示自动本地化为指定Locale对象的人类语言和文化规范的ZonedDateTime对象的内容。

分区ID和区域设置附加到调用程序员传递的日期时间格式。

我这里的代码基于Vaadin Ltd公司发布的代码,这些代码是在GitHub网站上找到的LocalDateTimeRenderer类源代码。

我删减了那个类的API。他们的API允许传递格式化模式字符串,而不是DateTimeFormatter对象。我认为渲染器不应该负责从这样的字符串生成格式化程序对象,因此也不应该处理由此产生的任何错误情况。它们的API允许传递一个区域设置对象。可以将Locale对象附加到调用程序员传递的DateTimeFormatter对象。我看不出这个呈现器类应该如何在将传递的区域设置分配给传递的格式化程序时不必要地参与进来。调用程序可以在将格式化程序传递给呈现程序之前完成该赋值。

以下是在Vaadin 14中定义InstantTrenderer的典型用法,用于渲染要在网格中显示的Instant对象。

invoicesGrid
        .addColumn(
                new InstantRenderer <>( Invoice :: getWhenCreated ,
                        DateTimeFormatter
                                .ofLocalizedDateTime( FormatStyle.SHORT , FormatStyle.MEDIUM )
                                .withLocale( Locale.CANADA_FRENCH )
                                .withZone( ZoneId.of( "America/Montreal" ) )
                )
        )
        .setHeader( "Created" )
;

大陆/地区的格式指定适当的时区名称,例如America/蒙特利尔Africa/CasablancaPacific/Auckland。永远不要使用2-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

请注意,java.time类使用不可变对象。with Zonewith Locale方法会生成一个新的DateTimeForey,而不是更改原始的。因此,您可能希望保留一个全局单例DateTimeForey,并偏好短日期和长时间的一天。

DateTimeFormatter f = DateTimeFormatter
                                .ofLocalizedDateTime( 
                                    FormatStyle.SHORT ,   // Length of date portion.
                                    FormatStyle.MEDIUM    // Length of time-of-day portion.
                                )
;

然后在代码的其他地方,应用每个用户自己的首选区域和区域设置。由于java.time.中使用的不可变对象模式,您会得到另一个专门的对象,而原始对象不受影响

invoicesGrid
        .addColumn(
                new InstantRenderer <>( Invoice :: getWhenCreated ,
                        f
                                .withLocale( user.getPreferredLocale()  )
                                .withZone( user.getPreferredZone() )
                )
        )
        .setHeader( "Created" )
;

顺便说一下,构造函数还有第三个可选参数:一个字符串,用于渲染的即时对象为null的情况。默认情况下,不向用户显示任何文本,这是一个空字符串。如果愿意,您可以传递一些其他字符串,例如null或void。

这是我的类的源代码。请注意,我在顶部附近的Javadoc中放了一些讨论。

我使用与Vaadin Ltd相同的Apache License 2,因此您可以自己使用和更改此代码。欢迎您的反馈。

package work.basil.example.ui;

/*
 * Copyright 2000-2020 Vaadin Ltd.
 * Copyright 2020 Basil Bourque.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */


import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
import java.util.Objects;

import com.vaadin.flow.data.renderer.BasicRenderer;
import com.vaadin.flow.function.ValueProvider;

/*
 * This class is based on source-code directly copied from
 * `LocalDateTimeRenderer.java` of Vaadin 14.1.x
 * as written and published by Vaadin Ltd. from their GitHub page.
 *
 * https://github.com/vaadin/flow/blob/master/flow-data/src/main/java/com/vaadin/flow/data/renderer/LocalDateTimeRenderer.java
 *
 * I re-purposed that class to handle `Instant` objects rather than `LocalDateTime`
 * objects. An `Instant` represents a moment, whereas `LocalDateTime` cannot because
 * of it lacking any concept of time zone or offset-from-UTC. In contrast, `Instant`
 * represents a moment in UTC (an offset-from-UTC of zero hours-minutes-seconds).
 *
 * By default, a `Instant` object renders in Vaadin by way of its `toString` method
 * generating text in standard ISO 8601 format YYYY-MM-DDTHH:MM:SS.SSSSSSSSSZ.
 *
 * If you want other than ISO 8601 format in UTC, use this class. In this class, we
 * apply  a time zone (`ZoneId`) to the `Instant` to adjust from UTC.
 *
 * The `ZoneId` object comes from one of three places:
 *  - Passed implicitly by being set as a property on a `DateTimeFormatter`
 *    object passed as an argument. This is the best case.
 *  - Defaults to calling `ZoneId.systemDefault` if  not found
 *    on the `DateTimeFormatter` object  (where `getZone` returns null).
 *
 * I deleted the constructors taking a formatting pattern string. Parsing such a string
 * and instantiating a `DateTimeFormatter` and handling resulting error conditions
 * should *not* be the job of this class. I believe the Vaadin team made a poor choice
 * in having constructors taking a string formatting pattern rather than just a
 * `DateTimeFormatter` object.
 *
 * Locale is another critical issue. A `Locale` object determines:
 *
 * (a) The human language used for translating items such as name of month and
 * name of day.
 *
 * (b) The cultural norms used in deciding localization issues such as the ordering
 * of elements (ex: day comes before or after month), abbreviation, capitalization,
 * punctuation, and so on.
 *
 * Again, I deleted the constructors taking a `Locale` object. The `DateTimeFormatter`
 * object passed by the calling programmer carries a `Locale`. That calling programmer
 * should have attached their intended locale object to that `DateTimeFormatter` object
 * by calling `DateTimeFormatter::withLocale`. Usually a `DateTimeFormatter` has a default
 * `Locale` assigned. But if found lacking, here we attach the JVM’s current default locale.
 *
 * Following the logic discussed above, I chose to not take a `ZoneId` as an argument.
 * A `ZoneId` can be attached to the `DateTimeFormatter` by calling `withZoneId`.
 * If the passed `DateTimeFormatter` is found lacking, here we attach the JVM’s current
 * default time zone.
 *
 * Typical usage, passing 2 arguments, a method reference and a `DateTimeFormatter` object
 * while omitting 3rd optional argument for null-representation to go with an blank empty string:
 *
 *     myGrid
 *          .addColumn(
 *                  new InstantRenderer <>( TheBusinessObject :: getWhenCreated ,
 *                          DateTimeFormatter
 *                                  .ofLocalizedDateTime( FormatStyle.SHORT , FormatStyle.MEDIUM )
 *                                  .withLocale( Locale.CANADA_FRENCH )
 *                                  .withZone( ZoneId.of( "America/Montreal" ) )
 *                  )
 *         )
 *
 * This code is written for Java 8 or later.
 *
 *  For criticisms and suggestions, contact me via LinkedIn at:  basilbourque
 */

/**
 * A template renderer for presenting {@code Instant} objects.
 *
 * @param <SOURCE> the type of the input item, from which the {@link Instant}
 *                 is extracted
 * @author Vaadin Ltd
 * @since 1.0.
 */
public class InstantRenderer < SOURCE >
        extends BasicRenderer < SOURCE, Instant >
{
    private DateTimeFormatter formatter;
    private String nullRepresentation;

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the format style
     * {@code FormatStyle.LONG} for the date and {@code FormatStyle.SHORT} for
     * time, with an empty string as its null representation.
     *
     * @param valueProvider the callback to provide a {@link Instant} to the
     *                      renderer, not <code>null</code>
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/FormatStyle.html#LONG">
     * FormatStyle.LONG</a>
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/FormatStyle.html#SHORT">
     * FormatStyle.SHORT</a>
     */
    public InstantRenderer (
            ValueProvider < SOURCE, Instant > valueProvider )
    {
        this(
                valueProvider ,
                DateTimeFormatter
                        .ofLocalizedDateTime( FormatStyle.LONG )
                        .withZone( ZoneId.systemDefault() )
                        .withLocale( Locale.getDefault() ) ,
                ""
        );
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given formatter, with the
     * empty string as its null representation.
     *
     * @param valueProvider the callback to provide a {@link Instant} to the
     *                      renderer, not <code>null</code>
     * @param formatter     the formatter to use, not <code>null</code>
     */
    public InstantRenderer (
            ValueProvider < SOURCE, Instant > valueProvider ,
            DateTimeFormatter formatter
    )
    {
        this(
                valueProvider ,
                formatter ,
                ""
        );
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given formatter.
     *
     * @param valueProvider      the callback to provide a {@link Instant} to the
     *                           renderer, not <code>null</code>
     * @param formatter          the formatter to use, not <code>null</code>
     * @param nullRepresentation the textual representation of the <code>null</code> value
     */
    public InstantRenderer (
            final ValueProvider < SOURCE, Instant > valueProvider ,
            final DateTimeFormatter formatter ,
            final String nullRepresentation
    )
    {
        super( valueProvider );

        this.formatter = Objects.requireNonNull( formatter , "formatter may not be null" );
        this.nullRepresentation = Objects.requireNonNull( nullRepresentation , "null-representation may not be null" );

        // If the formatter provided by the calling programmer lacks a time zone, apply the JVM's current default zone.
        // This condition is less than ideal. The calling programmer should have set an appropriate zone.
        // Often the appropriate zone is one specifically chosen or confirmed by the user.
        if ( Objects.isNull( this.formatter.getZone() ) )
        {
            this.formatter = this.formatter.withZone( ZoneId.systemDefault() );
        }

        // If the formatter provided by the calling programmer lacks a locale, apply the JVM's current default locale.
        // This condition is less than ideal. The calling programmer should have set an appropriate locale.
        // Often the appropriate locale is one specifically chosen or confirmed by the user.
        if ( Objects.isNull( this.formatter.getLocale() ) )
        {
            this.formatter = this.formatter.withLocale( Locale.getDefault() );
        }
    }


    @Override
    protected String getFormattedValue ( final Instant instant )
    {
        // If null, return the null representation.
        // If not null, adjust the `Instant` from UTC into the time zone attached to the `DateTimeFormatter` object.
        // This adjustment, made by calling `Instant::atZone`, produces a `ZonedDateTime` object.
        // We then create a `String` with text representing the value of that `ZonedDateTime` object.
        // That text is automatically localized per the `Locale` attached to the `DateTimeFormatter` object.
        String s = Objects.isNull( instant ) ? nullRepresentation : formatter.format( instant.atZone( this.formatter.getZone() ) );
        return s;
    }
}

也许我以后可以为另一个java做类似的事情。问题中列出的时间类型。

 类似资料:
  • 我希望以(或)的格式,以60秒为增量生成两个日期之间的日期+时间列表。 到目前为止,我已经能够使用对象生成两个日期之间的所有日期: } 但是,我希望修改它,以便它每次使用对象以60秒的增量生成(即,它将生成1440个值,而不是每天生成一个值,因为假设开始和结束时间只有一天,每小时有60分钟,每天24小时) 谢谢

  • 我需要一些解释为什么这个代码不编译: 错误: 类型Duration中的(TemporalAmount)方法不适用于参数(ChronoUnit) 正如本文所述: public static Duration from(TemporalAmount amount)从时间量中获取持续时间的实例。这将根据指定的金额获得持续时间。TemporalAmount表示一个时间量,可以是基于日期的,也可以是基于时间

  • 主要内容:Date 类,Calendar 类在 Java 中获取当前时间,可以使用 java.util.Date 类和 java.util.Calendar 类完成。其中, Date 类主要封装了系统的日期和时间的信息,Calendar 类则会根据系统的日历来解释 Date 对象。下面详细介绍这两个类的具体使用。 Date 类 Date 类表示系统特定的时间戳,可以精确到毫秒。Date 对象表示时间的默认顺序是星期、月、日、小时、分、秒、年

  • 问题内容: 我有一个脚本,需要在脚本的不同行执行以下命令: 在我的陈述中,我有以下内容: 我收到以下错误: 如果我将语句的顺序更改为: 我收到以下错误: 如果我再次将语句更改为: 我收到以下错误: 这是怎么回事,我怎么都可以工作? 问题答案: 您的麻烦是,您有一些代码希望对 模块 进行引用,而其他代码希望对类进行引用 。 显然,不能两者兼有。 当您这样做时: 您首先要设置为对该类的引用,然后立即将

  • 我有一个很长的时间戳1499070300(相当于星期一,03 Jul 2017 16:25:00 0800),但当我将其转换为LocalDateTime时,我得到1970-01-18T16:24:30.300 这是我的代码

  • 介绍 日期时间包是Hutool的核心包之一,提供针对JDK中Date和Calendar对象的封装,封装对象如下: 日期时间工具 DateUtil 针对日期时间操作提供一系列静态方法 DateTime 提供类似于Joda-Time中日期时间对象的封装,继承自Date类,并提供更加丰富的对象方法。 FastDateFormat 提供线程安全的针对Date对象的格式化和日期字符串解析支持。此对象在实际使