blob: d675af4b4420ae6720b5ee84cbd595c7d8a78970 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.daffodil.processors.unparsers
import org.apache.daffodil.calendar.DFDLCalendar
import org.apache.daffodil.exceptions.Assert
import org.apache.daffodil.io.DataOutputStream
import org.apache.daffodil.io.FormatInfo
import org.apache.daffodil.processors.ElementRuntimeData
import org.apache.daffodil.schema.annotation.props.gen.BinaryCalendarRep
import org.apache.daffodil.util.Maybe.One
import org.apache.daffodil.util.Misc
import com.ibm.icu.util.Calendar
case class ConvertBinaryCalendarSecMilliUnparser(
override val context: ElementRuntimeData,
binCalRep: BinaryCalendarRep,
epochTimeMillis: Long,
lengthInBits: Int,
hasTZ: Boolean)
extends PrimUnparser {
/**
* Primitive unparsers must override runtimeDependencies
*/
override lazy val runtimeDependencies = Vector()
protected def putNumber(dos: DataOutputStream, value: Long, nBits: Int, finfo: FormatInfo): Boolean = {
dos.putLong(value, nBits, finfo)
}
def unparse(state: UState): Unit = {
val node = state.currentInfosetNode.asSimple
val calValue = node.dataValue.getAnyRef match {
case dc: DFDLCalendar => dc.calendar
case x => Assert.invariantFailed("ConvertBinaryCalendar received unsupported type. %s of type %s.".format(x, Misc.getNameFromClass(x)))
}
// Adjust the time based on time zone - if a time zone wasn't specified, Calendar will assume the default
// time zone for the user instead of TimeZone.UNKNOWN_ZONE so we need to adjust to get the correct time
// Note that setting the correct time zone for the calendar will not adjust the time.
val epochTime = if (!hasTZ) {
val tz = calValue.getTimeZone
val gmtOffset = calValue.get(Calendar.ZONE_OFFSET)
val dstOffset = if (tz.inDaylightTime(calValue.getTime)) tz.getDSTSavings else 0
epochTimeMillis - (gmtOffset + dstOffset)
} else {
epochTimeMillis
}
val diff: Long = binCalRep match {
case BinaryCalendarRep.BinarySeconds => (calValue.getTimeInMillis - epochTime) / 1000
case BinaryCalendarRep.BinaryMilliseconds => (calValue.getTimeInMillis - epochTime)
case _ => Assert.impossibleCase
}
val dos = state.dataOutputStream
val res = putNumber(dos, diff, lengthInBits, state)
if (!res) {
Assert.invariant(dos.maybeRelBitLimit0b.isDefined)
UnparseError(One(state.schemaFileLocation), One(state.currentLocation), "Insufficient space to unparse element %s, required %s bits, but only %s were available.",
context.dpathElementCompileInfo.namedQName.toPrettyString, lengthInBits, dos.maybeRelBitLimit0b.get)
}
}
}