GSON по умолчанию сериализатор даты зависит от региона - PullRequest
0 голосов
/ 02 ноября 2019

В моем Java-приложении я использовал REST API, который возвращал данные в формате JSON, и заметил, что этот конкретный API форматировал свои даты особым образом: «1 ноября 2019 года», но проблема в том, что фактическая дата на сервере"2019-11-02". Это означает, что дата начала свёрнута до предыдущей даты. Мой сервер находится в другой стране. Ниже приведен полный json, полученный после форматирования.

jsonAccts [{"id":8,"userId":2,"departmentId":45,"effectiveFrom":"Jun 9, 2019","endsOn":"Nov 1, 2019","createdBy":2,"createdOn":"2019-11-02 05:34:11"}]

Имею эту проблемуна все поля даты. Какое решение для этого. Мне нужно получить ту же дату в базе данных по запросу REST API. Ниже приведен код, который я использовал для форматирования gson.

    Gson gson;
    GsonBuilder builder;
    SimpleDateFormat dtf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
    SimpleDateFormat dtfDate=new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
    String jsonAccts = null;
    try{
        builder = new GsonBuilder();
        builder.registerTypeAdapter(Timestamp.class, new JsonSerializer<Timestamp>() {
            @Override
            public JsonElement serialize(Timestamp src, Type typeOfSrc, JsonSerializationContext context) {
                dtf.setTimeZone(TimeZone.getTimeZone("UTC"));
                String jsDate = dtf.format(src);
                return new JsonPrimitive(jsDate);
            }
        });
        gson = builder.create();
        List<ClassTeacher> allActPgmMap = new ArrayList<ClassTeacher>();
        allActPgmMap = springDao.getClassTeacherList(Integer.parseInt(deptId));
        Type listType = new TypeToken<List<ClassTeacher>>() {}.getType();
        jsonAccts = gson.toJson(allActPgmMap, listType);
    }catch(Exception e){
        e.printStackTrace();
    }
    return jsonAccts;

Ниже приведен класс ClassTeacher.

import javax.persistence.*;
    import java.io.Serializable;
    import java.sql.Timestamp;
    import java.util.Date;

    @Entity
    @Table(name = "class_teacher")
    public class ClassTeacher implements Serializable,Comparable {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private long id;

        @Column(name = "user_id")
        private long userId;

        @Column(name = "department_id")
        private long departmentId;

        @Column(name = "effective_from")
        @Temporal(TemporalType.DATE)     
        private Date effectiveFrom;

        @Column(name = "ends_on")
        @Temporal(TemporalType.DATE)     
        private Date endsOn;

        @Column(name="created_by")
        private long createdBy;

        @Column(name="created_on")
        private Timestamp createdOn;

        public ClassTeacher() {

        }

        public ClassTeacher(long id, long departmentId, long userId, Date effectiveFrom, Date endsOn, long createdBy, Timestamp createdOn) {
            this.id = id;
            this.departmentId = departmentId;
            this.userId = userId;
            this.effectiveFrom = effectiveFrom;
            this.endsOn = endsOn;
            this.createdBy = createdBy;
            this.createdOn = createdOn;
        }

        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }

        public long getUserId() {
            return userId;
        }

        public void setUserId(long userId) {
            this.userId = userId;
        }

        public long getDepartmentId() {
            return departmentId;
        }

        public void setDepartmentId(long departmentId) {
            this.departmentId = departmentId;
        }

        public Date getEffectiveFrom() {
            return effectiveFrom;
        }

        public void setEffectiveFrom(Date effectiveFrom) {
            this.effectiveFrom = effectiveFrom;
        }

        public Date getEndsOn() {
            return endsOn;
        }

        public void setEndsOn(Date endsOn) {
            this.endsOn = endsOn;
        }

        public long getCreatedBy() {
            return createdBy;
        }

        public void setCreatedBy(long createdBy) {
            this.createdBy = createdBy;
        }

        public Timestamp getCreatedOn() {
            return createdOn;
        }

        public void setCreatedOn(Timestamp createdOn) {
            this.createdOn = createdOn;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            ClassTeacher that = (ClassTeacher) o;

            if (id != that.id) return false;
            if (createdBy != that.createdBy) return false;
            if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
            if (departmentId != null ? !departmentId.equals(that.departmentId) : that.departmentId != null) return false;
            if (effectiveFrom != null ? !effectiveFrom.equals(that.effectiveFrom) : that.effectiveFrom != null)
                return false;
            if (endsOn != null ? !endsOn.equals(that.endsOn) : that.endsOn != null) return false;
            if (createdOn != null ? !createdOn.equals(that.createdOn) : that.createdOn != null) return false;
        }

        @Override
        public int hashCode() {
            int result = (int) (id ^ (id >>> 32));
            result = 31 * result + (userId != null ? userId.hashCode() : 0);
            result = 31 * result + (departmentId != null ? departmentId.hashCode() : 0);
            result = 31 * result + (effectiveFrom != null ? effectiveFrom.hashCode() : 0);
            result = 31 * result + (endsOn != null ? endsOn.hashCode() : 0);
            result = 31 * result + (int) (createdBy ^ (createdBy >>> 32));
            result = 31 * result + (createdOn != null ? createdOn.hashCode() : 0);
            return result;
        }

        @Override
        public int compareTo(Object comparestu) {
            return this.getEffectiveFrom().compareTo(((ClassTeacher)comparestu).getEffectiveFrom());
        }
    }

Ответы [ 2 ]

0 голосов
/ 09 ноября 2019

Ваша проблема идет еще глубже, чем эта. форматирование любого типа объекта даты или времени без учета смещения часового пояса всегда неоднозначно. этот момент времени:

1.1.1970 00:00

можно интерпретировать (в UTC) как что-то от

1.1.1970 14:00 (in kiribati, UTC+14)

до

31.12.1969 12:00 (in honolulu, UTC -12)

, чтобы быть точным, вы быДОЛЖНО включать ЛИБО смещение часового пояса:

1970-01-01T00:00:00+00:00

соответствующий стандарт - ISO 8601 (https://en.wikipedia.org/wiki/ISO_8601), ИЛИ вы передаете ссылку как часть вашего контракта интерфейса (т. е. в документации, скажите что-нибудьстроки «все даты указаны в UTC»), что, честно говоря, довольно громоздко.

В большинстве ситуаций я сейчас использую миллисекунды эры или секунды эры для дат в API. Это делает его более понятнымкакой точный момент времени вы имеете в виду.

в некоторых ситуациях (например, при расчете часов работы магазина) вам также необходимо хранить информацию о часовом поясе отдельно и в идеале как конкретную ссылку на географический регион. местоположение (в форме «Америка / Нью-Йорк», а не «EST»), поскольку переход на летнее время может отличаться в зависимости от региона, даже если эти регионы иногда используют EST (например, в большинстве мест в США есть летнее время, в то время как в некоторых местах в Канаде EST остается в течение всего года) - дальнейшее чтение по http://web.cs.ucla.edu/~eggert/tz/tz-link.htm

объекту Java даты не знает о часовых поясах, пока вы не отформатируете его,в этот момент он (по умолчанию) использует системный часовой пояс для создания форматера по умолчанию.

то же самое относится и к датам синтаксического анализа: после синтаксического анализа вся информация о часовом поясе теряется.

TLDR:

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

все это не относится конкретно к вашей проблеме, поскольку вы спрашиваете, как настроить GSON для использования сериализатора и десериализатора в глобальном масштабе. как обычно, это зависит от того, кто делает де / сериализацию.

эта статья может немного помочь:

https://futurestud.io/tutorials/gson-advanced-custom-serialization-part-1

однако я считаю, что подход "эра миллисекунды" намного проще: просто объявите поле типа "long"в качестве даты, и конвертировать в дату, когда вам это нужно. это также отлично работает для запросов к БД с <и>

0 голосов
/ 04 ноября 2019

Проблема в том, что сервер возвращает дату как «1 ноября 2019 года». В этом формате у вас нет времени и часового пояса, поэтому вы не сможете правильно отформатировать дату. Если вы не можете изменить серверную часть, я не вижу никакого решения, иначе есть несколько решений:

1) Когда вы сделаете звонок, отправьте локаль на сервер, и он вернет вамправильная дата.

2) Измените формат даты сервера, либо верните время в миллисекундах, либо в формате ISO 8061 . Затем, когда вы будете анализировать дату, вы можете установить свой язык.

...