Why OpenFeign Misinterprets Dates and How to Fix It

When converting Date parameters in OpenFeign calls, the client serializes them to strings using the local CST timezone, causing a 14‑hour discrepancy that can be resolved by using timestamps, @DateTimeFormat, or custom formatters on both client and server sides.

Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Why OpenFeign Misinterprets Dates and How to Fix It

Introduction

During a migration from a monolithic to a micro‑service architecture, the project used OpenFeign for inter‑service calls. While development proceeded smoothly, passing a Date parameter caused unexpected time differences.

Problem Reproduction

Version information:

spring‑boot: 2.1.10.RELEASE

spring‑cloud: Greenwich.SR5

spring‑cloud‑alibaba: 2.1.2.RELEASE

Feign Service (Server)

application.yml

server:
  port: 3001
spring:
  application:
    name: feign-service

# nacos config
cloud:
  nacos:
    discovery:
      server-addr: localhost:8800

Startup class

@SpringBootApplication
@EnableDiscoveryClient // register service to Nacos
@Slf4j
public class FeignServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignServiceApplication.class, args);
        log.info("feign服务已启动...");
    }
}

Controller

@RestController
@RequestMapping("/api")
@Slf4j
public class FeignServiceController {
    @RequestMapping(value = "service/test", method = RequestMethod.GET)
    public void feignDateTest(@RequestParam("date") Date date) {
        log.info("传递过来的时间参数:{}", date);
    }
}

Feign Client

application.yml

server:
  port: 3002
spring:
  application:
    name: client-service

# nacos config
cloud:
  nacos:
    discovery:
      server-addr: localhost:8800

Startup class

@SpringBootApplication
@EnableFeignClients // scan @FeignClient interfaces
@Slf4j
public class FeignClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignClientApplication.class, args);
    }
}

Controller

@RestController
@RequestMapping("/api")
@Slf4j
public class FeignClientController {
    @Autowired
    IFeignClient iFeignClient;

    @RequestMapping(value = "test", method = RequestMethod.GET)
    public void feignDateTest() {
        Date date = new Date();
        log.info("date参数:{}", date);
        // call server
        iFeignClient.feignDateTest(date);
    }
}

Running both services and invoking http://localhost:3002/api/test produced two different timestamps, differing by 14 hours.

Root Cause Analysis

OpenFeign converts Date objects to String before transmission. The default conversion uses the JVM’s default timezone. In China the timezone is CST (UTC+8), but the string "CTS" is ambiguous and the parser interprets it as Central Standard Time (UTC‑6), adding a 14‑hour offset.

During network communication only textual data can be transmitted, so Java’s Date must be formatted to a string (often using the ISO‑8601 pattern) before being sent. The server receives the string and constructs a new Date via the deprecated Date(String) constructor, which internally calls parse(String) . If no explicit timezone is supplied, the parser uses the local timezone, leading to the observed discrepancy.

The legacy parse(String) method relies on the timezone offset embedded in the string; because "CTS" is interpreted as the US Central time zone, the conversion adds 14 hours (UTC+8 vs UTC‑6).

Solutions

Solution 1: Use Timestamps or Plain Strings

Transmit the time as a long timestamp (milliseconds since epoch) or as a plain formatted string, and convert it to Date on the server side.

Solution 2: Use @DateTimeFormat

Annotate the method parameter with @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") so Spring parses the incoming string with the correct pattern and timezone.

// Client interface
@FeignClient(name = "feign-service")
public interface IFeignClient {
    @RequestMapping(value = "/api/service/test", method = RequestMethod.GET)
    void feignDateTest(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @RequestParam("date") Date date);
}

// Server controller
@RestController
@RequestMapping("/api")
@Slf4j
public class FeignServiceController {
    @RequestMapping(value = "service/test", method = RequestMethod.GET)
    public void feignDateTest(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @RequestParam("date") Date date) {
        log.info("传递过来的时间参数:{}", date);
    }
}

Solution 3: Custom Date Formatter for Feign

Register a custom Converter that formats Date to a specific string on the client side and a matching converter that parses the string back to Date on the server side.

// Client side – register Date → String converter
@Component
public class DateFormatRegister implements FeignFormatterRegistrar {
    @Override
    public void registerFormatters(FormatterRegistry registry) {
        registry.addConverter(Date.class, String.class, new Date2StringConverter());
    }
    private static class Date2StringConverter implements Converter<Date, String> {
        @Override
        public String convert(Date source) {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(source);
        }
    }
}
// Server side – register String → Date converter
@Configuration
public class String2DateConfig {
    @Autowired
    private RequestMappingHandlerAdapter handlerAdapter;

    @PostConstruct
    public void initEditableValidation() {
        ConfigurableWebBindingInitializer initializer =
            (ConfigurableWebBindingInitializer) handlerAdapter.getWebBindingInitializer();
        if (initializer.getConversionService() != null) {
            GenericConversionService conversionService =
                (GenericConversionService) initializer.getConversionService();
            conversionService.addConverter(String.class, Date.class, new String2DateConverter());
        }
    }
    private static class String2DateConverter implements Converter<String, Date> {
        @Override
        public Date convert(String source) {
            try {
                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(source);
            } catch (ParseException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
}

After applying any of the above solutions, the timestamps from client and server match.

Now the time values are consistent and the issue is resolved.

JavamicroservicesSpring BootOpenFeigndate handlingFeignClient
Xuanwu Backend Tech Stack
Written by

Xuanwu Backend Tech Stack

Primarily covers fundamental Java concepts, mainstream frameworks, deep dives into underlying principles, and JVM internals.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.