ICU-21590 Add skeleton syntax for integer-width-trunc
diff --git a/docs/userguide/format_parse/numbers/skeletons.md b/docs/userguide/format_parse/numbers/skeletons.md
index fa30ba1..3ef41c2 100644
--- a/docs/userguide/format_parse/numbers/skeletons.md
+++ b/docs/userguide/format_parse/numbers/skeletons.md
@@ -299,6 +299,7 @@
 | `integer-width/##0` | - | Between 1 and 3 <br/> integer digits | `IntegerWidth::zeroFillTo(1)` <br/> `.truncateAt(3)`
 | `integer-width/00` | - | Exactly 2 <br/> integer digits | `IntegerWidth::zeroFillTo(2)` <br/> `.truncateAt(2)` |
 | `integer-width/*` | - | Zero or more <br/> integer digits | `IntegerWidth::zeroFillTo(0) `
+| `integer-width-trunc` | - | Zero integer digits | `IntegerWidth::zeroFillTo(0)` <br/> `.truncateAt(0)`
 
 The long-form option starts with either a single `*` symbol, signaling no limit
 on the number of integer digits (no *`truncateAt`*), or zero or more `#` symbols.
@@ -310,6 +311,8 @@
 The concise skeleton is simply one or more `0` characters. This supports
 minimum integer digits but not maximum integer digits.
 
+The special stem `integer-width-trunc` covers the case when both *`truncateAt`* and *`zeroFillTo`* are zero.
+
 ***Prior to ICU 67***, use the symbol `+` instead of `*`.
 
 ### Scale
diff --git a/icu4c/source/i18n/number_skeletons.cpp b/icu4c/source/i18n/number_skeletons.cpp
index 97d7430..0aa03f5 100644
--- a/icu4c/source/i18n/number_skeletons.cpp
+++ b/icu4c/source/i18n/number_skeletons.cpp
@@ -74,6 +74,7 @@ void U_CALLCONV initNumberSkeletons(UErrorCode& status) {
     b.add(u"rounding-mode-half-down", STEM_ROUNDING_MODE_HALF_DOWN, status);
     b.add(u"rounding-mode-half-up", STEM_ROUNDING_MODE_HALF_UP, status);
     b.add(u"rounding-mode-unnecessary", STEM_ROUNDING_MODE_UNNECESSARY, status);
+    b.add(u"integer-width-trunc", STEM_INTEGER_WIDTH_TRUNC, status);
     b.add(u"group-off", STEM_GROUP_OFF, status);
     b.add(u"group-min2", STEM_GROUP_MIN2, status);
     b.add(u"group-auto", STEM_GROUP_AUTO, status);
@@ -700,6 +701,11 @@ skeleton::parseStem(const StringSegment& segment, const UCharsTrie& stemTrie, Se
             macros.roundingMode = stem_to_object::roundingMode(stem);
             return STATE_NULL;
 
+        case STEM_INTEGER_WIDTH_TRUNC:
+            CHECK_NULL(seen, integerWidth, status);
+            macros.integerWidth = IntegerWidth::zeroFillTo(0).truncateAt(0);
+            return STATE_NULL;
+
         case STEM_GROUP_OFF:
         case STEM_GROUP_MIN2:
         case STEM_GROUP_AUTO:
@@ -1677,10 +1683,15 @@ bool GeneratorHelpers::integerWidth(const MacroProps& macros, UnicodeString& sb,
         // Error or Default
         return false;
     }
+    const auto& minMaxInt = macros.integerWidth.fUnion.minMaxInt;
+    if (minMaxInt.fMinInt == 0 && minMaxInt.fMaxInt == 0) {
+        sb.append(u"integer-width-trunc", -1);
+        return true;
+    }
     sb.append(u"integer-width/", -1);
     blueprint_helpers::generateIntegerWidthOption(
-            macros.integerWidth.fUnion.minMaxInt.fMinInt,
-            macros.integerWidth.fUnion.minMaxInt.fMaxInt,
+            minMaxInt.fMinInt,
+            minMaxInt.fMaxInt,
             sb,
             status);
     return true;
diff --git a/icu4c/source/i18n/number_skeletons.h b/icu4c/source/i18n/number_skeletons.h
index af63650..a34e424 100644
--- a/icu4c/source/i18n/number_skeletons.h
+++ b/icu4c/source/i18n/number_skeletons.h
@@ -92,6 +92,7 @@ enum StemEnum {
     STEM_ROUNDING_MODE_HALF_DOWN,
     STEM_ROUNDING_MODE_HALF_UP,
     STEM_ROUNDING_MODE_UNNECESSARY,
+    STEM_INTEGER_WIDTH_TRUNC,
     STEM_GROUP_OFF,
     STEM_GROUP_MIN2,
     STEM_GROUP_AUTO,
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index b0aa5b4..cc07d85 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -3838,6 +3838,41 @@ void NumberFormatterApiTest::integerWidth() {
             // Note: this double produces all 17 significant digits
             10000000000000002000.0,
             u"00");
+
+    assertFormatDescending(
+            u"Integer Width Double Zero (ICU-21590)",
+            u"integer-width-trunc",
+            u"integer-width-trunc",
+            NumberFormatter::with()
+                .integerWidth(IntegerWidth::zeroFillTo(0).truncateAt(0)),
+            Locale::getEnglish(),
+            u"0",
+            u"0",
+            u".5",
+            u".65",
+            u".765",
+            u".8765",
+            u".08765",
+            u".008765",
+            u"0");
+
+    assertFormatDescending(
+            u"Integer Width Double Zero with minFraction (ICU-21590)",
+            u"integer-width-trunc .0*",
+            u"integer-width-trunc .0*",
+            NumberFormatter::with()
+                .integerWidth(IntegerWidth::zeroFillTo(0).truncateAt(0))
+                .precision(Precision::minFraction(1)),
+            Locale::getEnglish(),
+            u".0",
+            u".0",
+            u".5",
+            u".65",
+            u".765",
+            u".8765",
+            u".08765",
+            u".008765",
+            u".0");
 }
 
 void NumberFormatterApiTest::symbols() {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberSkeletonImpl.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberSkeletonImpl.java
index 54555d8..c9e0369 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberSkeletonImpl.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberSkeletonImpl.java
@@ -96,6 +96,7 @@ static enum StemEnum {
         STEM_ROUNDING_MODE_HALF_DOWN,
         STEM_ROUNDING_MODE_HALF_UP,
         STEM_ROUNDING_MODE_UNNECESSARY,
+        STEM_INTEGER_WIDTH_TRUNC,
         STEM_GROUP_OFF,
         STEM_GROUP_MIN2,
         STEM_GROUP_AUTO,
@@ -174,6 +175,7 @@ static String buildStemTrie() {
         b.add("rounding-mode-half-down", StemEnum.STEM_ROUNDING_MODE_HALF_DOWN.ordinal());
         b.add("rounding-mode-half-up", StemEnum.STEM_ROUNDING_MODE_HALF_UP.ordinal());
         b.add("rounding-mode-unnecessary", StemEnum.STEM_ROUNDING_MODE_UNNECESSARY.ordinal());
+        b.add("integer-width-trunc", StemEnum.STEM_INTEGER_WIDTH_TRUNC.ordinal());
         b.add("group-off", StemEnum.STEM_GROUP_OFF.ordinal());
         b.add("group-min2", StemEnum.STEM_GROUP_MIN2.ordinal());
         b.add("group-auto", StemEnum.STEM_GROUP_AUTO.ordinal());
@@ -751,6 +753,11 @@ private static ParseState parseStem(StringSegment segment, CharsTrie stemTrie, M
             macros.roundingMode = StemToObject.roundingMode(stem);
             return ParseState.STATE_NULL;
 
+        case STEM_INTEGER_WIDTH_TRUNC:
+            checkNull(macros.integerWidth, segment);
+            macros.integerWidth = IntegerWidth.zeroFillTo(0).truncateAt(0);
+            return ParseState.STATE_NULL;
+
         case STEM_GROUP_OFF:
         case STEM_GROUP_MIN2:
         case STEM_GROUP_AUTO:
@@ -1623,6 +1630,10 @@ private static boolean integerWidth(MacroProps macros, StringBuilder sb) {
             if (macros.integerWidth.equals(IntegerWidth.DEFAULT)) {
                 return false; // Default
             }
+            if (macros.integerWidth.minInt == 0 && macros.integerWidth.maxInt == 0) {
+                sb.append("integer-width-trunc");
+                return true;
+            }
             sb.append("integer-width/");
             BlueprintHelpers.generateIntegerWidthOption(macros.integerWidth.minInt,
                     macros.integerWidth.maxInt,
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
index 4f910da..9cf6e61 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
@@ -3799,6 +3799,41 @@ public void integerWidth() {
                 // Note: this double produces all 17 significant digits
                 10000000000000002000.0,
                 "00");
+
+        assertFormatDescending(
+                "Integer Width Double Zero (ICU-21590)",
+                "integer-width-trunc",
+                "integer-width-trunc",
+                NumberFormatter.with()
+                        .integerWidth(IntegerWidth.zeroFillTo(0).truncateAt(0)),
+                ULocale.ENGLISH,
+                "0",
+                "0",
+                ".5",
+                ".65",
+                ".765",
+                ".8765",
+                ".08765",
+                ".008765",
+                "0");
+
+        assertFormatDescending(
+                "Integer Width Double Zero with minFraction (ICU-21590)",
+                "integer-width-trunc .0*",
+                "integer-width-trunc .0*",
+                NumberFormatter.with()
+                        .integerWidth(IntegerWidth.zeroFillTo(0).truncateAt(0))
+                        .precision(Precision.minFraction(1)),
+                ULocale.ENGLISH,
+                ".0",
+                ".0",
+                ".5",
+                ".65",
+                ".765",
+                ".8765",
+                ".08765",
+                ".008765",
+                ".0");
     }
 
     @Test