Java 时区国际化处理

跨时区系统设计方案 划分时区作用是为了统一时间,让各个区域12点都是正中午的时候,其实我没想明白为什么这么折腾,我这边18点是正中午有什么不可以的呢,这世界就是这样总喜欢把简单的事情搞复杂了,时区的划分以地球表面按经线从东到西划成一个个区域,每隔经度15°划分一个时区,规定相邻区域的时间相差1小时,,如下图所示。门店收银系统分布在澳洲、中国、新西兰,分跨不同时区,系统需要显示不同时区的时间,这是比较折腾的一件事,今天讲一下我们是怎么作的。4、门店表配置了对应时区,比如 Perth时区是东八区,Jindalee 是东十区等。 阅读详情

前言

项目主打海外业务,不可避免碰到时区的问题。目前的解决方案是,服务器、数据库统一设置为0时区,前端提交日期格式的字符串参数,请求头传递时区的参数(如:东八区【+8】,西一区【-1】),后台根据偏移量将日期字符串转换成0时区的Date

切面


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.TimeZone;


/**
 * @author 
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class TimeZoneAspect {
    private final ThreadLocal<CtlHeaderTrackAnno> localTrackAnno = new ThreadLocal<>();


    private static final String BEGIN_TIME = "beginTime";
    private static final String END_TIME = "endTime";

    private static final String START_DATE = "startDate";
    private static final String END_DATE = "endDate";

    @Pointcut("@annotation(com.test.test.service.core.security.annotation.TimeZone)")
    public void timeZone() {
        // For Aspect
    }

    @Before("timeZone()")
    public void runBefore(JoinPoint joinPoint) {

        Object arg = joinPoint.getArgs()[0];
        if(arg instanceof BaseRequest){
            BaseRequest baseRequest = (BaseRequest) arg;
            this.formatDateByTimeZone(baseRequest.getParams());
        }else if(arg instanceof BaseEntity){
            BaseEntity baseEntity = (BaseEntity) arg;
            this.formatDateByTimeZone(baseEntity.getParams());
        }
    }

    private void formatDateByTimeZone(Map<String, Object> params) {
        String timezone = Objects.requireNonNull(ServletUtils.getRequest()).getHeader(HeaderConst.X_TIME_ZONE);
        // 根据时区转换日期字符串
        if(params.containsKey(BEGIN_TIME) && params.containsKey(END_TIME) && StrUtil.isNotBlank(timezone)){
            Object begin = params.get(BEGIN_TIME);
            Object end = params.get(END_TIME);
            Date startDate = LocalDateTimeUtils.parseV2(begin.toString(), DatePattern.NORM_DATETIME_PATTERN, Integer.parseInt(timezone));
            Date endDate = LocalDateTimeUtils.parseV2(end.toString(), DatePattern.NORM_DATETIME_PATTERN, Integer.parseInt(timezone));
            params.put(START_DATE, startDate);
            params.put(END_DATE, endDate);
        }
    }

}

工具类



import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.TimeZone;

public class LocalDateTimeUtils {

	public static String formatObject(Object date, String pattern, Integer offset) {
		if (date == null || StrUtil.isBlank(pattern) || offset == null) {
			return "";
		}
		if (date instanceof Date) {
			return format((Date) date, pattern, offset);
		}
		else if (date instanceof String) {
			return formatString((String) date, pattern, offset);
		}
		return "";
	}

	public static String format(Date date, String pattern, Integer offset) {
		if (date == null || StrUtil.isBlank(pattern) || offset == null) {
			return "";
		}
		TimeZone tz = TimeZone.getTimeZone("UTC");
		if (offset != null) {
			tz.setRawOffset(-offset * 60 * 1000);
		}
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		sdf.setTimeZone(tz);
		String d = sdf.format(date);
		return d;
	}

	public static String showAsTimezone(Integer offset) {
		if (offset == null) {
			return "";
		}
		String returnVal = "UTC";
		if (offset > 0) {
			returnVal += "-";
		}
		else {
			returnVal += "+";
		}
		offset = Math.abs(offset);
		int hour = offset / 60;
		if (hour >= 10) {
			returnVal += hour + ":";
		}
		else {
			returnVal += "0" + hour + ":";
		}
		int minute = offset % 60;
		if (minute >= 10) {
			returnVal += minute;
		}
		else {
			returnVal += "0" + minute;
		}
		return returnVal;
	}

	public static String formatString(String dateString, String pattern, Integer offset) {
		if (StrUtil.isBlank(dateString) || StrUtil.isBlank(pattern) || offset == null) {
			return "";
		}
		SimpleDateFormat sdfWithTimeZone = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
		sdfWithTimeZone.setTimeZone(TimeZone.getTimeZone("UTC"));
		Date date = null;
		try {
			date = sdfWithTimeZone.parse(dateString);
		} catch (ParseException e) {
			return "";
		}

		TimeZone tz = TimeZone.getTimeZone("UTC");
		if (offset != null) {
			tz.setRawOffset(-offset * 60 * 1000);
		}
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		sdf.setTimeZone(tz);
		String d = sdf.format(date);
		return d;
	}

	public static Date parse(String dateStr, String pattern, Integer offset) {
		if (StrUtil.isBlank(dateStr) || StrUtil.isBlank(pattern) || offset == null) {
			return null;
		}
		TimeZone tz = TimeZone.getTimeZone("UTC");
		tz.setRawOffset(-offset * 60 * 1000);
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		sdf.setTimeZone(tz);
		Date d = null;
		try {
			d = sdf.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return d;
	}

	public static Date parseV2(String dateStr, String pattern, Integer offset) {
		if (StrUtil.isBlank(dateStr) || StrUtil.isBlank(pattern) || offset == null) {
			return null;
		}
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		ZoneId zoneId = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(offset));
		TimeZone timeZone = TimeZone.getTimeZone(zoneId);
		sdf.setTimeZone(timeZone);
		Date d = null;
		try {
			d = sdf.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return d;
	}

	public static void main(String[] args) {
		// 前台请求日期
		Object begin = "2023-02-02 00:00:00";
		Object end = "2023-02-02 23:59:59";
		// 操作系统置为0时区
		TimeZone.setDefault(TimeZone.getTimeZone("GMT+0:00"));
		// 模拟东8区请求【比0时区快了8小时】(0时区转东八区,+8;东八区转0时区,-8)
		Date startDate = LocalDateTimeUtils.parseV2(begin.toString(), DatePattern.NORM_DATETIME_PATTERN, Integer.parseInt("8"));
		Date endDate = LocalDateTimeUtils.parseV2(end.toString(), DatePattern.NORM_DATETIME_PATTERN, Integer.parseInt("8"));
//		Wed Feb 01 16:00:00 GMT+00:00 2023
//		Thu Feb 02 15:59:59 GMT+00:00 2023
		System.out.println(startDate);
		System.out.println(endDate);

		// 模拟西1区请求【比0时区慢了1小时】(0时区转西一区,-1;西一区转0时区,+1)
		Date startDate1 = LocalDateTimeUtils.parseV2(begin.toString(), DatePattern.NORM_DATETIME_PATTERN, Integer.parseInt("-1"));
		Date endDate1 = LocalDateTimeUtils.parseV2(end.toString(), DatePattern.NORM_DATETIME_PATTERN, Integer.parseInt("-1"));
//		Thu Feb 02 01:00:00 GMT+00:00 2023
//		Fri Feb 03 00:59:59 GMT+00:00 2023
		System.out.println(startDate1);
		System.out.println(endDate1);
	}

}

滚雪球学Java(108):在Java中,如何使用DateFormat和SimpleDateFormat处理不同地区的日期和时间格式化? 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 阅读详情

相关推荐

Java Calendar类详细解析与应用

在Java中,日期和时间的处理一直是程序员面临的挑战之一。早期的Java版本中,类是处理日期时间的主要工具。但随着Java 1.1的发布,引入了Calendar类,其提供了更加丰富的时间处理功能,与Date类相比,Calendar提供了更大的灵活性,例如可以单独设置日期和时间的各个字段。Unix时间戳源于Unix和类Unix系统,最初由Unix的创始人之一Dennis Ritchie提出。它是一个32位的整数,从1970年1月1日00:00:00 UTC开始计数秒数。

weixin_29097457的博客 1197

Java时区国际化解决方案

本篇文章对国际化场景中,接口请求接收和返回体中包含的时间字符串值如何根据时区自动转换进行了总结,至于系统如何设置和获取Locale和TimeZone对象,计划另起一篇文章介绍.文中有所欠缺和错误的地方,欢迎各位留言补充指正.

qq_27990381的博客 4368

java国际化&时间处理

NULL 博文链接:https://hoochiang.iteye.com/blog/1848534

java 多时区客户的统一处理详解

涉及到多国化的网站,不仅要考虑语言多国化,还要考虑时间的通用性。   首先,要记住: JAVA的 System CurrentTime 就是 utc 的时间。 我们的目的就是要保证服务器存的时间为UTC时间(为什么要强调这句?因为时间是客户输入的,比如一个搜索功能中,客户要查询某个时间段的数据),而数据显示的时候是根据客户的时区来显示的。     分为 服务端: 又分为system ...

zhizhesky的专栏 532

Java对世界不同时区timezone之间时间转换的处理方法

主要介绍了Java对世界不同时区timezone之间时间转换的处理方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

Day2 十分钟带你解决逆向中对称加密算法 (RC4)

在密码学中,RC4(来自Rivest Cipher 4的缩写)是一种串流加密算法,密钥长度可变。他加密解密使用相同的密钥,因此也被称为“流加密算法”。RC4由伪随机数生成器和异或运算组成。RC4的密钥长度可变,范围是[1,255]。RC4一个字节一个字节地加解密。给定一个密钥,伪随机数生成器接受密钥并产生一个S盒。S盒用来加密数据,而且在加密过程中S盒会变化。由于异或运算的对合性,RC4加密解密使用同一套算法。

m0_73779708的博客 1289

java时区_java国际化之时区问题处理

Etc/GMT+12Etc/GMT+11MITPacific/ApiaPacific/MidwayPacific/NiuePacific/Pago_PagoPacific/SamoaUS/SamoaAmerica/AdakAmerica/AtkaEtc/GMT+10HSTPacific/FakaofoPacific/HonoluluPacific/JohnstonPacific/Rarotonga...

weixin_35186171的博客 2226

E2000 RGMII0通讯异常问题总结

飞腾E2000 RGMII接YT8521,RGMII0路不通问题。

乌拉大喵喵 1624

java国际化之时区问题处理

在国际化的项目中需要处理的日期时间问题主要有两点: 1、日期时间的国际化格式问题处理; 2、日期时间的时区问题处理,这两个问题要区分开,不要弄混了。 日期时间国际化化格式处理 对应的关键词:Locale 日期时间的国际化格式指的是在不同的国家和地区对日期时间的显示方式不同,主要通过不同国家地区不同的语言习惯,对同一个实现的呈现方式不同。在java中需要结合Locale类进行处...

persistence勿忘初心 6963

【机器人】机械臂控制入门技术栈分享

机械臂控制入门技术栈分享1.前言2.机器人控制入门技术栈2.1.空间描述和变化2.2.运动学分析2.3.动力学建模2.4.控制入门学习3.进阶部分3.1.机器人参数辨识3.2.非线性控制3.3.现代机器人描述方法:指数坐标4.总结 1.前言 今天看到优快云上有个分享个人技术栈的活动,虽然我不是一个正规的程序员,也不搞前端、后端这些,但我一直在优快云上通过写博客对我的学习进行总结,于是我突发奇想,不如我也写一下我的个人技术栈,针对机械臂控制入门的,因为我水平也不高,所以本文内容也许不够饱满,也不够准确,但

要恰饭得嘛 5854

【计算机三级-数据库技术】操作题大题(第1套)

从触发器的语法中可知,【1】处应该填写的是执行触发器的表,【2】处应该填写指定在表或视图上执行哪些数据修改语句时将激活触发器的关键字。使用FOR或AFTER选顶定义的触发器为后触发器,即只有在引发触发器执行的语句中的操作都已成功执行,并且所有的约束检查也成功完成后,才执行触发器。转换成新的独立的模式,模式的属性由联系本身的属性及两个实体的键构成,主键由两端实体的键组合而成。实体的转换:在从ER图转换为关系模式时,一个实体转换成一个关系模式,实体的属性就是关系模式的属性,实体的键就是关系的主键。

放纵小开爱的博客 1100

时间国际化

时间国际化

wyazyf 285

国产SR8201F以太网PHY芯片调试避坑指南:从机贴失败到杜邦线救场的实战记录

本文详细介绍了国产SR8201F以太网PHY芯片的调试避坑指南,涵盖硬件设计、PCB布局、SMT贴片及软件驱动等关键环节。通过实战案例解析,帮助工程师解决MII/RMII接口配置、电源设计、信号完整性等典型问题,提升以太网通信稳定性与EMC性能。

c6d7e8f9g的博客 1212

Java时间处理2---时区TimeZone类方法探究

原文:优快云博主「Gene Xu> 原文链接:https://blog.youkuaiyun.com/goodbye_youth/article/details/81807273 一、TimeZone 类的定义 TimeZone 类位于 java.util 包中,是一个抽象类,主要包含了对于时区的各种操作,可以进行计算时间偏移量或夏令时等操作 二、TimeZone 类常用方法 getAvailableIDs() 获取」 Java支持的所有时区 ID System.out.println(Arrays.

LarsCheng's Blog 1561

百度百科 X-Bk-Token 算法还原

百度百科 X-Bk-Token 算法还原

自成背后的博客 1万+

AI上推荐 之 多任务loss优化(自适应权重篇)

1. 写在前面 在多任务学习中,往往会将多个相关的任务放在一起来学习。例如在推荐系统中,排序模型同时预估候选的点击率和浏览时间。相对于单任务学习,多任务学习有以下优势: 多个任务共享一个模型,占用内存量减少; 多个任务一次前向计算得出结果,推理速度增加; 关联任务通过共享信息,相互补充,可以提升彼此的表现。 前面的一篇文章,主要是从模型结构的角度聊了下多任务学习,介绍了工业界非常经典也常用的MMOE模型,然而,对于多任务学习, Loss的优化也非常重要, 因为我们知道通过多个目标去指导网络进行统一的训练

Miracle8070 1万+

Java中如何处理夏令时?

而2022-11-15 10:20:00 这个时间,London的时区offset为Z(即Zero 零),即没有向前调整(不是夏令时)从上面的输出可以看出,要表示中国北京时区对应的ZoneId,ZoneId并不是Asia/Beijing,而是Asia/Shanghai。即:2022-10-15 10:20:00 这个时间,对于London来说,时区的offset为+1,即向前拨快了1小时(夏令时)伦敦 在2022-03-27 ~ 2002-10-30 为夏令时期间。

weixin_39158966的博客 1773

TPAMI 2024 | MO-MIX:基于深度强化学习的多目标多智能体协同决策

深度强化学习(RL)已被广泛应用于解决复杂的决策问题。在许多现实世界的场景中,任务通常有多个相互冲突的目标,并且可能需要多个智能体进行合作,这些是多目标多智能体决策问题。然而,在这个交叉领域的研究工作还相对较少。现有的方法仅限于单独的领域,并且只能处理具有单一目标的多智能体决策,或者具有单一智能体的多目标决策。在本文中,我们提出了MO-MIX来解决多目标多智能体强化学习(MOMARL)问题。我们的方法基于集中训练与分散执行(CTDE)框架。

小白学视觉 1128

Java国际化时间-理解时区、ZonedDateTime、OffsetDateTime

我国现在没有实行夏令时和冬令时,但是欧洲北美很多还是会实行夏令时和冬令时,亚洲像印度、巴基斯坦也实行夏令时和冬令时。例如,美国西5区,中国东8区,中国时间-13小时就是美国时间了,这对于冬令时没有问题,对于夏令时有问题。再说,美国不像中国统一用1个时区,不管你是在上海、北京、香港、台北用的都是东8区。每个地区可能夏令时和冬令时的规定也不太一样。所以,做国际化的时候一定要注意。所以在处理有夏令时和冬令时的地区的时候,不能简单的用offset来计算。美国用多个时区,例如纽约西5区,芝加哥中部时间用的是西6区。

trayvontang的博客 1692

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【Java】时区时间转换 Instant 和 LocalDateTime类的使用

Java 时间类的使用

12Dong的博客 6006

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

关于java Date和时区使用的总结

最近工作中一直在跟时区和时间转换的业务打交道,发现这篇文章总结的不错,转发记录一下。后续把自己的使用总结加上。 refs: http://blog.163.com/haizai219@126/blog/static/444125552009101924912981/ https://blog.youkuaiyun.com/henry_wu001/article/details/46757741 java2...

m0_37937353的博客 1113

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

java 时区 时间戳 时间

一 时区 国际标准规定, 全球一共分为24个时区,规定格林威治地区为0时区,每个相邻时区时间相差一个小时。 从0度时区开始 向东(向右)每跨一个时区,时间间隔加一小时, 共有十二个时区,叫作是东一区,东二区…东十二区。 向西(向左)每跨一个时区,时间间隔减一小时, 共有十二个区,叫作是西一区,西二区…,西十二区。 注意:(中国为了方便统一,虽然跨越5个时区,但都使用同一个时区时间) 在java 中 没有东西十二区的说法 直接 就是24个时区 二 时间戳 时间戳是计算机的一种计时方式, 指格林威治时间197

追梦程序员 2134

国际化动态文本(MessageFormat)的使用案例源码和国际化其他标签的使用

国际化动态文件和其他标签的实例应用 一  动态文件的概念 1.什么时候使用动态文本 如果字符串中包含了多个与国际化相关的数据,可以使用MessageFormat类对这些数据进行批量处理 ----比如一段字符串中包含时间、数字、货币、、可以进行批量处理   2.如何使用动态文本---批量处理 (1)MessageFormat类允许开发人员用占位符替换掉字符串中的敏感数据(即国际化相关的

韩晓爽的专栏 1183

Java日期相关类型

Java与日期相关的类型有: 1.Date类:·java.util.Date类用于表示特定的时间点,精确到毫秒,但不支持日期的国际化和分时区显示。·构造方法:public Date()、public  Date(long date)·主要功能方法:public int compareTo(Date anotherDate)                      publ

人生得意须尽欢,莫使金樽空对月~ 769

Java-TimeZone类,即java.util.TimeZone类

 转自: http://www.trainlinux.com/p/2002-10-12/6085.html  Java高级日期概念二 出自:zdnet 2002年10月12日 23:04 时区T

田田的菜坛子 1万+
上一篇: RestTemplate PUT方式上传文件
下一篇: docker学习(十四)docker安装kafka
宁漂打工仔
博客等级 码龄9年 1万+粉丝 153原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宁漂打工仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值