Json 严格模式下的MongoDB日期格式

Json 严格模式下的MongoDB日期格式,json,mongodb,mongodb-java,Json,Mongodb,Mongodb Java,使用MongoDB java驱动程序,在文档上应用toJson()方法将获得该文档的JSON表示,JsonMode设置为STRICT。 以下历元格式用于日期:{“$date”:“DateAsmillseconds”} 使用mongoexport,我们得到一个ISO-8601格式 见官方文件(): 在严格模式下,日期是ISO-8601日期格式,在模板YYYY-MM-DDTHH:MM:ss.mmm之后有一个强制时区字段 MongoDB JSON解析器目前不支持加载表示Unix纪元之前日期的ISO-

使用MongoDB java驱动程序,在文档上应用toJson()方法将获得该文档的JSON表示,JsonMode设置为STRICT。 以下历元格式用于日期:{“$date”:“DateAsmillseconds”}

  • 使用mongoexport,我们得到一个ISO-8601格式

  • 见官方文件():

    • 在严格模式下,日期是ISO-8601日期格式,在模板YYYY-MM-DDTHH:MM:ss.mmm之后有一个强制时区字段

    • MongoDB JSON解析器目前不支持加载表示Unix纪元之前日期的ISO-8601字符串。设置历元前日期和超过系统时间类型可容纳的日期的格式时,使用以下格式: {“$date”:{“$numberLong”:“dateasmillseconds”}

  • 如果有人能解释一下为什么MongoDB java驱动程序、mongoexport工具和官方文档之间没有通用格式,我将不胜感激

    谢谢

    显然,Java驱动程序没有很好的理由偏离官方规范。唯一的例外是那些不能用ISO8601格式表示的日期(如B.C.日期…)

    作为解决方法,我扩展了
    JsonWriter
    类,并提供了两个
    toJson
    静态方法作为如何使用它的示例:

    package whatever.package.you.like;
    
    import java.io.IOException;
    import java.io.StringWriter;
    import java.io.Writer;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.TimeZone;
    
    import org.bson.BSONException;
    import org.bson.BsonContextType;
    import org.bson.BsonDocument;
    import org.bson.codecs.BsonDocumentCodec;
    import org.bson.codecs.EncoderContext;
    import org.bson.conversions.Bson;
    import org.bson.json.JsonMode;
    import org.bson.json.JsonWriter;
    import org.bson.json.JsonWriterSettings;
    
    import com.mongodb.MongoClient;
    
    /**
     * A {@link JsonWriter} extension that conforms to the "strict" JSON format
     * specified by MongoDB for data/time values.
     * 
     * The {@link JsonWriter} class provided in the MongoDB Java driver (version
     * 3.2.2) does not conform to official MongoDB specification for strict mode
     * JSON (see https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
     * This is specifically a problem with the date/time values which get filled
     * with a milliseconds value (i.e. {$date: 309249234098}) instead of the ISO8601
     * date/time (i.e. {$date: "2016-07-14T08:44:23.234Z"}) value which the
     * specification calls for. This extension of {@link JsonWriter} conforms to the
     * MongoDb specification in this regard.
     */
    public class ConformingJsonWriter extends JsonWriter {
       private final JsonWriterSettings settings;
    
       private final Writer writer;
    
       private boolean writingIndentedDateTime = false;
    
       /**
        * Creates a new instance which uses {@code writer} to write JSON to.
        *
        * @param writer
        *           the writer to write JSON to.
        */
       public ConformingJsonWriter(final Writer writer) {
          this(writer, new JsonWriterSettings());
       }
    
       /**
        * Creates a new instance which uses {@code writer} to write JSON to and uses
        * the given settings.
        *
        * @param writer
        *           the writer to write JSON to.
        * @param settings
        *           the settings to apply to this writer.
        */
       public ConformingJsonWriter(final Writer writer,
             final JsonWriterSettings settings) {
          super(writer, settings);
          this.writer = writer;
          this.settings = settings;
          setContext(new Context(null, BsonContextType.TOP_LEVEL, ""));
       }
    
       private void writeIndentation(int skip) throws IOException {
          for (Context context = getContext()
                .getParentContext(); context != null; context = context
                      .getParentContext()) {
             if (skip-- <= 0) {
                writer.write(settings.getIndentCharacters());
             }
          }
       }
    
       private static String millisToIso8601(long millis) throws IOException {
          SimpleDateFormat dateFormat = new SimpleDateFormat(
                "yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'");
          dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
          return dateFormat.format(new Date(millis));
       }
    
       @Override
       protected void doWriteDateTime(final long value) {
          if ((settings.getOutputMode() == JsonMode.STRICT)
                && (value >= -59014396800000L && value <= 253399536000000L)) {
             try {
                writeStartDocument();
                if (settings.isIndent()) {
                   writingIndentedDateTime = true;
                   writer.write(settings.getNewLineCharacters());
                   writeIndentation(0);
                } else {
                   writer.write(" ");
                }
                writer.write("\"$date\" : ");
                writer.write("\"");
                writer.write(millisToIso8601(value));
                writer.write("\"");
                writeEndDocument();
                writingIndentedDateTime = false;
             } catch (IOException e) {
                throw new BSONException("Wrapping IOException", e);
             }
          } else {
             super.doWriteDateTime(value);
          }
       }
    
       @Override
       protected void doWriteEndDocument() {
          if (writingIndentedDateTime) {
             try {
                writer.write(settings.getNewLineCharacters());
                writeIndentation(1);
                writer.write("}");
                if (getContext()
                      .getContextType() == BsonContextType.SCOPE_DOCUMENT) {
                   setContext(getContext().getParentContext());
                   writeEndDocument();
                } else {
                   setContext(getContext().getParentContext());
                }
             } catch (IOException e) {
                throw new BSONException("Wrapping IOException", e);
             }
          } else {
             super.doWriteEndDocument();
          }
       }
    
       /**
        * Take a {@link Bson} instance and convert it to "strict" JSON
        * representation with no indentation (read, "NOT pretty printed").
        * 
        * @param bson
        *           The {@link Bson} instance to convert
        * @return The JSON representation.
        */
       public static String toJson(Bson bson) {
          return toJson(bson, new JsonWriterSettings());
       }
    
       /**
        * Take a {@link Bson} instance and convert it to JSON representation.
        * 
        * @param bson
        *           The {@link Bson} instance to convert
        * @param writerSettings
        *           {@link JsonWriterSettings} that specify details about how the
        *           JSON output should look.
        * @return The JSON representation.
        */
       public static String toJson(Bson bson,
             final JsonWriterSettings writerSettings) {
          BsonDocumentCodec encoder = new BsonDocumentCodec();
          ConformingJsonWriter writer = new ConformingJsonWriter(new StringWriter(),
                writerSettings);
          encoder.encode(writer,
                bson.toBsonDocument(BsonDocument.class,
                      MongoClient.getDefaultCodecRegistry()),
                EncoderContext.builder().isEncodingCollectibleDocument(true)
                      .build());
          return writer.getWriter().toString();
       }
    }
    
    package which.package.you.like;
    导入java.io.IOException;
    导入java.io.StringWriter;
    导入java.io.Writer;
    导入java.text.simpleDataFormat;
    导入java.util.Date;
    导入java.util.TimeZone;
    导入org.bson.BSONException;
    导入org.bson.BsonContextType;
    导入org.bson.BsonDocument;
    导入org.bson.codecs.BsonDocumentCodec;
    导入org.bson.codecs.EncoderContext;
    导入org.bson.conversions.bson;
    导入org.bson.json.JsonMode;
    导入org.bson.json.JsonWriter;
    导入org.bson.json.JsonWriterSettings;
    导入com.mongodb.MongoClient;
    /**
    *符合“严格”JSON格式的{@link JsonWriter}扩展
    *由MongoDB为数据/时间值指定。
    * 
    *MongoDB Java驱动程序中提供的{@link JsonWriter}类(版本
    *3.2.2)不符合官方MongoDB严格模式规范
    *JSON(参见https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
    *这尤其是填充的日期/时间值的问题
    *使用毫秒值(即{$date:3092449234098})而不是ISO8601
    *日期/时间(即{$date:“2016-07-14T08:44:23.234Z”})值
    *规格要求。{@link JsonWriter}的这个扩展符合
    *MongoDb在这方面的规范。
    */
    符合JsonWriter的公共类扩展了JsonWriter{
    私有最终JsonWriterSettings设置;
    私人最终撰稿人;
    私有布尔writingIndentedDateTime=false;
    /**
    *创建一个新实例,该实例使用{@code writer}将JSON写入。
    *
    *@param writer
    *写入JSON的写入程序。
    */
    公开确认JSONWRITER(最终编写者){
    这个(writer,新的JsonWriterSettings());
    }
    /**
    *创建一个新实例,该实例使用{@code writer}将JSON写入并使用
    *给定的设置。
    *
    *@param writer
    *写入JSON的写入程序。
    *@param设置
    *要应用于此编写器的设置。
    */
    公开确认JSONWRITER(最终作者,
    最终JsonWriterSettings设置){
    超级(编写器、设置);
    this.writer=writer;
    this.settings=设置;
    setContext(新上下文(null,BsonContextType.TOP_LEVEL,“”);
    }
    私有void writeIndentation(int skip)引发IOException{
    for(Context=getContext()
    .getParentContext();上下文!=null;上下文=上下文
    .getParentContext()){
    如果(跳过--=-59014396800000L&&value