public static String formatDate(FldSimpleModel model, String format, Date date) {

    DateFormat dateFormat = null;
    if ((format != null) && (format.length() > 0)) {
      SimpleDateFormat simpleDateFormat = getSimpleDateFormat();
      simpleDateFormat.applyPattern(convertDatePattern(format));
      dateFormat = simpleDateFormat;
    } else {
      dateFormat =
          (model.getFldName().indexOf("DATE") > -1
              ? SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT)
              : SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT));
    }
    return dateFormat.format(date);
  }
  private static double getNumber(FldSimpleModel model, String value)
      throws FieldResultIsNotANumberException {

    WordprocessingMLPackage pkg = model.getWordMLPackage();
    String decimalSymbol = null;
    if (pkg != null && pkg.getMainDocumentPart().getDocumentSettingsPart() != null) {

      DocumentSettingsPart docSettingsPart = pkg.getMainDocumentPart().getDocumentSettingsPart();
      if (docSettingsPart.getJaxbElement().getDecimalSymbol() != null) {
        decimalSymbol = docSettingsPart.getJaxbElement().getDecimalSymbol().getVal();
      }
    }

    // For DOCPROPERTY field, and possibly some others, but not "=",
    // Word will parse "€180,000.00 EUR" as a number
    if (model.fldName.equals("DOCPROPERTY") || model.fldName.equals("MERGEFIELD")) {

      // First, parse the value
      NumberExtractor nex = new NumberExtractor(decimalSymbol);
      try {
        value = nex.extractNumber(value);
      } catch (java.lang.IllegalStateException noMatch) {
        // There is no number in this string.
        // In this case Word just inserts the non-numeric text,
        // without attempting to format the number
        throw new FieldResultIsNotANumberException("No number in " + value);
      }
    }

    try {
      return Double.parseDouble(value);
    } catch (Exception e) {
      // TODO: is it a bookmark?

      throw new FieldResultIsNotANumberException();
    }
  }
  private String getFormat(String instr, String val) throws TransformerException, Docx4JException {

    FldSimpleModel fsm = new FldSimpleModel();
    fsm.build(instr);
    return FormattingSwitchHelper.applyFormattingSwitch(null, fsm, val);
  }
  public static String formatDate(FldSimpleModel model, Date date) {

    String format = findFirstSwitchValue("\\@", model.getFldParameters(), true);
    return formatDate(model, format, date);
  }
  public static String applyFormattingSwitch(FldSimpleModel model, String value)
      throws Docx4JException {

    // date-and-time-formatting-switch: \@
    Date date = null;
    try {
      String dtFormat = findFirstSwitchValue("\\@", model.getFldParameters(), true);
      if (dtFormat == null) {
        // SPECIFICATION: If no date-and-time-formatting-switch is present,
        // a date or time result is formatted in an implementation-defined manner.

        // TODO .. analyse what Word does
        // for now, just leave as is
      } else if (dtFormat.equals("")) {
        // Verified with Word 2010 sp1 for DOCPROPERTY (very likely others are the same)
        return "Error! Switch argument not specified.";
      } else {
        log.debug("Applying date format " + dtFormat + " to " + value);
        date = getDate(model, value);

        // For \@ date formatting, Word seems to give same results for
        // DATE, DOCPROPERTY, and MERGEFIELD,
        // but to have a different code path for =

        // OK, its a date
        if (model.fldName.equals("=")) {
          // For =, today's date is used!
          date = new Date();
        }
        value = formatDate(model, dtFormat, date);
      }

    } catch (FieldResultIsNotADateOrTimeException e) {
      // SPECIFICATION: If the result of a field is not a date or time,
      // the date-and-time-formatting-switch has no effect
    }

    // numeric-formatting-switch: \#
    double number = -1;
    if (date == null) {
      // It is not a date, so see whether it is a number

      String nFormat = findFirstSwitchValue("\\#", model.getFldParameters(), true);
      if (nFormat != null) {

        if (nFormat.equals("")) {
          return "Error! Switch argument not specified.";
          // Verified with Word 2010 sp1, for =, DOCPROPERTY, MERGEFIELD
          // TODO unless it looks like a bookmark, eg {=AA \#} ?

        } else {

          try {
            number = getNumber(model, value);
          } catch (FieldResultIsNotANumberException e) {
            // Is value a bookmark?
            // If so TODO set value to bookmark contents
            // Otherwise
            log.debug(e.getMessage());
            // Word 2010 produces something like: "!Syntax Error"
            return "!Syntax Error";
          }

          value = formatNumber(model, nFormat, number);

          // SPECIFICATION: If no numeric-formatting-switch is present,
          // a numeric result is formatted without leading spaces or
          // trailing fractional zeros.
          // If the result is negative, a leading minus sign is present.
          // If the result is a whole number, no radix point is present.

          // We'll only honour this if the number is really a number.
          // Not, for example, CL.87559-p
          //					try {
          //						number = Double.parseDouble(value);
          //						value = formatNumber(model, "#.##########", number );
          //					} catch (Exception e) {
          //						log.debug(value + " is not a number");
          //					}

          // That's commented out, because in reality (Word 2010 sp1),
          // if there is no '\#', it is not treated as a number

        }
      }
    }

    // general-formatting-switch: \*
    // SPECIFICATION: A general-formatting-switch specifies a variety of
    // formats for a numeric or text result.  If the result type of a field
    // does not correspond to the format specified, this switch has no effect.

    //  Word 2010 can handle:
    //     \@ "d 'de' MMMM 'de' yyyy  " \* Upper"
    // (ie \@ and \* at same time)
    // but \@ must be before \*
    String gFormat = findFirstSwitchValue("\\*", model.getFldParameters(), false);
    value = gFormat == null ? value : formatGeneral(model, gFormat, value);

    log.debug("Result -> " + value + "\n");

    return value;
  }